Шаблон / идиома для обновлений функционального состояния в Clojure - PullRequest
2 голосов
/ 13 мая 2011

Я решил попробовать написать программу симуляции в Clojure (как подтверждение концепции), где:

  • Все состояние симуляции хранится в одной неизменной структуре данных
  • Обновления состояний представлены в виде функций, которые отображают состояние в следующее состояние

Это означает, что я мог бы написать функцию обновления как что-то вроде:

(defn example-update-function [old-state]
  (let [state (atom old-state)]
    (swap! state some-other-update-function-1)
    (if (some-condition @state)
      (swap! state some-conditional-update-function))
    (swap! state some-other-update-function-2)
    (reset! state (some-function @state some-other-param))
    @state))

Кажется, что подход работает, но следующее вызывает у меня две причины для беспокойства:

  • Мне приходится использовать изменяемый атом для управления промежуточными состояниями ... кажется, не очень функциональным!
  • Код кажется немного уродливым со всеми разыменованиями swap! S и @state.

Есть ли лучший / более элегантный подход?

Ответы [ 3 ]

5 голосов
/ 14 мая 2011

Вы могли бы написать это так:

  (defn change-when 
    "If (test val) is truethy, returns (fun val), else returns val"
    [val test fun] (if (test val) (fun val) val))

  (defn example-update-function [old-state]
    (-> old-state
        some-other-update-function-1
        (change-when some-condition some-conditional-update-function)
        some-other-update-function-2
        (some-function some-other-param)
        identity))

Возможно, на полпути к дороге монад ...

3 голосов
/ 14 мая 2011

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

get :: m s   
  -- Return the state from the internals of the monad.

put :: s -> m ()  
  -- Replace the state inside the monad.

modify :: (s -> s) -> m ()   
  -- Maps an old state to a new state inside a state monad. The old state is thrown away.

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

1 голос
/ 13 мая 2011

монады? Всем всегда нравится государственная монада, которая, как я понимаю, предназначена для такого рода вещей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...