2016-07-31 2 views
2

У меня есть атом с векторной величиной:Как вернуть разыменованное значение в качестве результата функции в Clojure

(def v (atom [1 2])) 

Я хочу, чтобы написать функцию, которая будет возвращать этот разыменованный атом. То есть, я в основном хочу написать функцию, которая будет возвращать один и тот же результат, как это:

=> @v 
[1 2] 

Мой первый дубль в этом было что-то вроде этого:

=> (let [f #(@v)] 
    (println (f))) 
ArityException Wrong number of args (0) passed to: PersistentVector clojure.lang.AFn.throwArity (AFn.java:429) 

Но это, конечно, не работа в качестве разыменованного атома не является функцией:

=> (@v) 
ArityException Wrong number of args (0) passed to: PersistentVector clojure.lang.AFn.throwArity (AFn.java:429) 

обходной я, наконец, в конечном итоге с такой:

=> (let [f #(vec @v)] 
    (println (f))) 
[1 2] 
nil 

... но, конечно, должен быть лучший способ сделать это, что не нужно предполагать, что значение атома является вектором?

+2

'(defn deref-v [] (deref v))' –

+1

Это просто функция 'deref'. Я не знаю, почему люди обертывают его функцией как annwer, но в любом случае вы упомянули в комментариях, что это упрощенный вопрос. Я думаю, вы слишком упростились, поэтому, возможно, отредактируйте и дайте нам более подробную информацию? как ваш вопрос в настоящее время стоит, 'deref' * является * функцией. И если вы просто используете 'deref', вы вообще не загрязняете свое пространство имен, и вы также можете просто быстро' deref' использовать макрос читателя '@'. – MasterMastic

+1

Это не просто функция 'deref'! Это не значит, что это аргумент, но 'v'. FWIW, вы также можете написать: '# (-> @v)' – ClojureMostly

ответ

2

Ни один из существующих ответов не дают два простых, самых сжатых решения, так что вот они.Как stated по @Stefan, вы хотите что-то эквивалентное эту функцию:

(fn [] (deref v)) 

Однако это использование deref именно случай использования, что @ читателя макросъемка предназначена для упрощения:

(fn [] @v) 

Или , так как (deref v) вызов функции, вы можете вместо этого использовать #() читателя макрос:

#(deref v) 

Главное, что вы не можете использовать как@, так и #()вместе в этом случае. Но это не значит, что вы не можете или не должны использовать один из них из них.

1

Иногда лучше оставить читателя конструкции, как # и @, и просто идти с функциями (или макросов и специальных форм):

user> (def v (atom [1 2])) 
#'user/v 
user> (let [f (fn [] (deref v))] (f)) 
[1 2] 

я беру это, что ваш пример очень упрощенная версия от того, что вы действительно хотите сделать. Если нет, deref может быть просто функцией, которую вы ищете.

+0

(deref @v) вместо @v, блестящий! Я знал, что должно быть простое решение. :) Да, мне понадобилось около недели или около того, чтобы узнать, какова моя настоящая проблема, и придумал упрощенный пример. – Domchi

+0

'(derev v)' not '(derev @v)'. '@' - это просто синтаксический сахар для 'deref', выполняемый/reader /. См. Раздел «Макросимволы» на http://clojure.org/reference/reader –

+0

Вы правы, я сделал опечатку в своем комментарии. Спасибо за ваш ответ, особенно за то, что напомнили мне, что иногда лучше оставить # и @ и использовать сами функции, так как для этого это и есть правильная ситуация. – Domchi

1

I want to write a function that will return this dereferenced atom

(def v (atom [1 2])) 
(defn foo [] @v) 
(foo) ;;=> [1 2] 
+0

Да! Я хотел пойти с анонимной функцией, чтобы я не загрязнял свое пространство имен функцией, которая вызывается только один раз, но ваш ответ дал мне идею просто использовать расширенную форму функции anon: (let [f (fn [] @v) ] (prn (f))) – Domchi

+0

@Domchi (пусть [f (fn [] @v)] (prn (f))) фактически совпадает с (prn @v) - почему функция? –

+0

Это упрощенный пример реального использования. Моим вариантом использования является то, что на самом деле у меня есть функция, которая что-то делает с атомом (в петле цикла), и я использую его в разных местах, передавая ему разные атомы. – Domchi

1

прежде всего: причиной этой ошибки является расширение синтаксиса лямбда-выражения сахара. Вы могли бы думать об этом так:

#(expression*) => (fn [] (expression*)) 

так, думая так:

#(@v) => (fn [] (@v)) и @v в свою очередь, расширяется до (deref v) (легко видеть с macroexpansion), что приведет вас к этой форме:

(fn [] ((deref v)))

на самом деле вы наполовину правы с предполагаемой причины ошибки: результат разыменования вызывается как функция, но на самом деле это может быть (как вектор га функциональная семантика), а просто не хватает обязательного параметра (именно то, что сказано в тексте ошибки). поэтому он должен работать для этого: #(@v 0) =>(fn [] ((deref v) 0))

user> (let [f #(@v 0)] 
     (println (f))) 
1 
nil 

лично я бы просто пойти с частичным применением вместо лямбда-выражения для решения этой проблемы:

user> (let [f (partial deref v)] 
     (println (f))) 
[1 2] 
nil 
+0

Я стою исправлено - это на самом деле довольно круто, конечно, он ожидает положение в векторе в качестве параметра. Спасибо за объяснение и идею частичного; Я всегда удивляюсь, как другие люди думают о той же проблеме. – Domchi

Смежные вопросы