2015-10-18 2 views
3

делает 'put' op в состоянии Monad (Haskell), обновляет фактическое состояние или просто возвращает новое состояние с новым значением? Мой вопрос в том, может ли государственная Монада использоваться как «глобальная переменная» в императивной обстановке? и «put» изменяет «глобальную переменную»?Haskell State Monad

Мое понимание было НЕТ, оно НЕ модифицирует initialState, но с использованием монадического интерфейса мы можем просто пропустить вычисления состояний b/w новых состояний, оставив исходное состояние «нетронутым». Это верно? если нет, пожалуйста, исправьте меня.

Спасибо.

ответ

4

Ответ в типах.

newtype State s a = State {runState :: s -> (a, s)} 

Таким образом, состояние, по существу, функция, которая принимает один параметр, «S» (которую мы называем состояние), и возвращает кортеж (значение, состояние). Монада реализована, как показано ниже

instance Monad (State s) where 
    return a = State $ \s -> (a,s) 
    (State f) >>= h = State $ \s -> let (a,s') = f s 
            in (runState h a) s' 

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

В настоящее время put является следующей функцией.

put newState = State $ \s -> ((),newState) 

Это по существу устанавливает состояние, которая будет передана к следующей функции в составе и функциям ниже по потоку будет видеть модифицированное состояние.

Фактически, государственная монада полностью чиста (то есть ничего не устанавливается); только то, что передается нисходящим изменениям. Другими словами, государственная монада спасает вас от несанкционированного переноса состояния на чистом языке, таком как Haskell. Другими словами, государственная монада просто предоставляет интерфейс, который скрывает детали потоковой передачи состояния (это то, что вызывается в WikiBooks и, как я полагаю, выучите вам Haskell).

Следующие действия показаны в действии. У вас есть значение, которое устанавливает поле значения таким же, как поле состояния (обратите внимание, что когда я имею в виду установку, я имею в виду вывод, а не переменную). put получает состояние через переданное ему значение, увеличивает его и устанавливает состояние с этим новым значением.

-- execState :: State s a -> s -> s 
let x = get >>= \x -> put (x+10) 
execState x 10 

Вышеприведенные выходы 20.

Теперь, давайте сделаем следующее.

execState (x >> x) 10 

Это даст выход 30. Первый x устанавливает состояние до 20 с помощью надетой. Это теперь используется вторым x. В этой точке get устанавливает, что состояние передало его в поле значений, которое теперь равно 20. Теперь наш put получит это значение, увеличит его на 10 и установит в качестве нового состояния.

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

5

В State ничего не найдено. Вы могли бы реализовать это следующим образом:

newtype State s a = State {runState :: s -> (a, s)} 

То есть, State s a (мы думаем, как вычисление, которое использует состояние типа s для получения результата типа a) только функция, которая принимает состояние и возвращает результат и новое состояние. Вы должны попытаться записать экземпляр Monad и определения get и put для этого определения. Настоящее определение более общее:

type State s = StateT s Identity 
newtype Identity a = Identity a 
newtype StateT s m a = StateT {runStateT :: s -> m (a, s)} 

Это позволяет добавлять состояние к другим монадическим вычислениям. Также можно определить трансформаторы состояния как «рабочие монады». У Apfelmus есть учебник по тем местам.

1

Во-первых, государство не является «глобальным» как таковым; вы могли бы иметь несколько разных копий государственной монады, каждая со своим независимым государством, и они не будут мешать друг другу. (Действительно, это, возможно, все.) Если вы хотите, чтобы состояние было глобальным для всей программы, вам нужно было бы перевести всю программу в единую государственную монаду.

Во-вторых, вызов put изменяет результат, после которого последуют вызовы get. Это все. Он не «меняет» фактическое значение. Например, если вы вызываете get и поместите результат в переменную где-нибудь, а затем вызовите put, ваша переменная не изменится. Даже если состояние - это словарь или что-то еще, если вы должны добавить новый ключ и put, то любой, кто все еще смотрит на старую копию словаря, по-прежнему будет видеть старый словарь. Это не является особым для государственной монады; это как раз то, как работает Haskell.

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