2016-10-05 11 views
0

EDIT:Clojure изменить обновление в возвращает NIL и dosync оленья кожа позволяют повторялись

dosync создает себя функцию так, чтобы вызовы recur интерпретируются как вызовы, сделанные в функции dosync генерируемой.

Это след функции, которую я фактически сделал. Полагаю, что это как можно проще.

(defn change-to-ref [ref data] 
    (dosync 
    (if-let [[new-ref new-data] (some-test @ref data)] 
     (recur new-ref new-data) 
     (alter ref f data)))) 

Исключение:

CompilerException java.lang.IllegalArgumentException: 
Mismatched argument count to recur, expected: 0 args, got: 2 

ORIGINAL:

Я пытался обновить HashMap в исх следующим

(def example-ref (ref {:some {:nested {:structure}}})) 
(defn f [this] [this]) ;; just an example function 

(sync (alter example-ref update-in [:some] f) 

user=> nil 

Что было весьма удивительно, как должно» ve возвращается

user=> {:some [{:nested {:structure}}]} 

Так чем я пытался:

(update-in @example-ref [:some] f) 

user=> {:some [{:nested {:structure}}]} 

Но чем я читал, что alter звонки apply так:

(apply update-in @example-ref '([:some] f)) 

user=> {:some nil} 

Хорошо, так что давайте делать это правильный путь:

(apply update-in @example-ref (list [:some] f)) 

user=> {:some [{:nested {:structure}}]} 

Ну, это здорово, я понял это, , но это не объясняет, почему это происходит Ронг в alter , и я даже не могу изменить его в любом случае ...

(apply (fn [a b] (update-in a b f)) @example-ref '([:something])) 

user=> {:some [{:nested {:structure}}]} 

Это выглядит ужасно, но по крайней мере это работает, и я могу имитировать его alter: D

(sync (alter example-ref (fn [a b] (update-in a b f)) [:some]) 

user=> nil 

Ok, ты победил.

Я взглянул на: clojure.lang.Ref.alter source но не стал мудрее. (кроме того, что, на мой взгляд, alter на самом деле не звонит apply)

Я надеюсь, что некоторые из вас поймут это и ответят, что такое правильный код.

+0

Что вы имеете в виду при использовании 'recur' внутри' dosync'? Вам действительно нужны вложенные транзакции? – OlegTheCat

+1

@OlegTheCat Я на самом деле делаю да, у меня есть вложенная структура ссылок и вы хотите найти последнюю в пути, чтобы я изменил ее, проблема решена btw просто, убедившись, что вызов функции в dosync. – user5211470

+0

@OlegTheCat btw Я согласен с вашим вопросом, если я буду запускать транзакцию, а затем повторю, это не будет хорошей идеей, так как транзакция всегда является одной (в хвостовой позиции). Я думаю, что это нормально, может быть, ее лучше если я сделал отдельную чистую функцию для поиска по пути – user5211470

ответ

0

Проблема заключается в том, что подпись sync выглядит следующим образом:

(синхронизированная флаги игнорируемых-для-теперь & тела)

Первый аргумент этого макроса игнорируется.Также документация рекомендует пройти nil для него:

транзакционные-флаги => TBD, передать ноль сейчас

Таким образом, правильный способ использования sync будет:

> (sync nil (alter example-ref update-in [:some] (partial conj []))) 
{:some [{:nested {:structure :foo}}]} 

I 'd также рекомендуют использовать dosync вместо sync (просто чтобы не испортить первый параметр, по существу эти функции are the same):

> (dosync (alter example-ref update-in [:some] (partial conj []))) 
{:some [{:nested {:structure :foo}}]} 
+0

На самом деле я использовал dosync раньше, но это дало ошибку в том, что recur вызывается с неправильным количеством аргументов, читайте, что dosync делает анонимную функцию, знаете ли вы, как обойти это? – user5211470

+0

Можете ли вы отредактировать свой вопрос и поставить MCVE, который вызывает проблему с 'dosync'? – OlegTheCat

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

  • Нет связанных вопросов^_^