Создание ссылок с преобразователями
Можно ли создать ref
с преобразователем в Clojure, способом, аналогичным созданию chan
с преобразователем?
т.е. когда вы создаете chan
с помощью преобразователя он фильтрует / отображает все входы в выходы.
Я ожидаю, что есть также способ создать ref
таким образом, что бы вы ни установили, он может либо игнорировать, либо изменять ввод. Возможно ли это сделать?
2 ответа
Добавление преобразователя в канал изменяет содержимое по мере их прохождения, что примерно аналогично добавлению отслеживания к ссылке, которая применяет свои собственные изменения при каждом изменении значения. Это изменение само по себе запускает часы снова, поэтому будьте осторожны, чтобы не взорвать стек, если они рекурсивные.
user> (def r (ref 0))
#'user/r
user> (add-watch r :label
(fn [label the-ref old-state new-state]
(println "adding that little something extra")
(if (< old-state 10) (dosync (commute the-ref inc)))))
#<Ref@1af618c2: 0>
user> (dosync (alter r inc))
adding that little something extra
adding that little something extra
adding that little something extra
adding that little something extra
adding that little something extra
adding that little something extra
adding that little something extra
adding that little something extra
adding that little something extra
adding that little something extra
adding that little something extra
1
user> @r
11
Вы даже можете применить преобразователь к состоянию атома, если хотите.
Это интересная идея, но это неправильный путь, по крайней мере, по нескольким причинам. Вы потеряете некоторые отношения, которые ожидаете сохранить:
(alter r identity) =/= r
(alter r f)(alter r f) =/= (alter r (comp f f))
(alter r f) =/= (ref-set r (f @r))
Кроме того, некоторые преобразователи являются летучими веществами с побочными эффектами, и не имеют никакого отношения к dosync
блок. т.е. если вы используете (take n)
как ваш преобразователь, то если ваш dosync
не удастся, тогда он будет повторяться, как будто вызывается с (take (dec n))
, который нарушает dosync
требования к кузову.
Проблема заключается в ref
позволяет читать и писать как отдельные шаги. Если бы вместо этого было что-то основополагающее, которое позволяло бы вам "применить" входные данные к скрытому "состоянию" и собрать выходные данные все за один шаг, в соответствии с STM, тогда с этим можно было бы работать.