Объем государственной монады

Я пытаюсь понять, что происходит в следующем коде, код работает правильно, но я пытаюсь понять почему.

import Control.Monad.State
import System.IO
import System.Environment

echoArgs :: [String] -> State Int [String]
echoArgs x = loopArgs x >> return x
      where loopArgs [] = return () 
            loopArgs s@(x':xs') = modify (+1) >> loopArgs xs'

main :: IO () 
main = do 
    argv <- getArgs
    let s = echoArgs argv
    mapM_ putStr' (evalState s 0) 
    putStrLn $ "\nNum Args = " ++ show (execState s 0) 
    where putStr' x = putStr $ x ++ " "

Чего я не понимаю, так это почему состояние монады State не "сбрасывается" при каждом последующем вызове loopArgs. Передается ли состояние как переменная с каждым >>, и если да, то может ли кто-нибудь показать мне, как это сделать?


person hcaulfield57    schedule 02.03.2014    source источник


Ответы (1)


Передается ли состояние как переменная с каждым >>, и если да, то может ли кто-нибудь показать мне, как это сделать?

Это действительно так. Полезно взглянуть на игрушечную реализацию монады State.

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

instance Monad (State s) where
  return a = State $ \s -> (a, s)

  State act >>= k = State $ \s ->
    let (a, s') = act s
    in runState (k a) s'

get :: State s s
get = State $ \s -> (s, s)

put :: s -> State s ()
put s = State $ \_ -> ((), s)

modify :: (s -> s) -> State s ()
modify f = get >>= \x -> put (f x)

Когда вы выполняете привязку с использованием >>= или >>, накопленное состояние передается в качестве аргумента функции с правой стороны.

Когда вы запускаете execState или evalState, он просто извлекает либо результирующее значение, либо состояние из результирующего кортежа.

execState :: State s a -> s -> s
execState act = snd . runState act

evalState :: State s a -> s -> a
evalState act = fst . runState act
person Stephen Diehl    schedule 03.03.2014
comment
Спасибо за ответ, есть ли пример работы >> (в монаде State), я понял как работает >>= из вашего примера, состояние каждый раз проходит. - person hcaulfield57; 03.03.2014
comment
>> — это всего лишь частный случай >>=, он определяется как m >> k = m >>= \_ -> k - person Stephen Diehl; 03.03.2014
comment
Ах да, но это все равно проходит по состоянию, спасибо! - person hcaulfield57; 03.03.2014
comment
Прости за этого Стивена! - person hcaulfield57; 03.03.2014