Понимание государственного аргумента в государственной монаде - PullRequest
5 голосов
/ 20 мая 2019

Я так стараюсь обернуть голову вокруг Государственной Монады, и я не понимаю следующее:

Учитывая реализацию return и (>>=), когда вы говорите State $ \s ->...., откуда берется s? Я имею в виду, когда вы начинаете выполнять >>= ... >>=, разве это не значит, что где-то в начале вашей цепочки вы как-то должны указывать этот начальный параметр?

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

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

В (>>=) вы говорите State $ \s -> runState m s, и я не получаю , когда называется тот начальный (\s -> ...) argumentREAL argument)?

Может кто-нибудь объяснить, пожалуйста?

Позже Редактировать :

Может кто-нибудь показать мне, как будет установлено состояние initial, скажем, если ему нужно получить значение, используя getLine?

main::IO()
main=do
  argument<-getLine
  --how do i set initial state with argument?
  m >> f1 >> f2 >> f3

Ответы [ 3 ]

5 голосов
/ 20 мая 2019

когда вы говорите State $ \s ->...., откуда берется s?

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

st = do { x <- get ; return (x+1) }

x = runState st 0    -- x is (1,0)

Я также ощущаю еще одно возможное недоразумение с вашей стороны: вы пишете: " когда называется этот начальный (\s -> ...) argument?" Там нет «первоначальной» лямбды: все лямбды вложены внутрь!

do { a <- as; b <- bs; c <- foo b; return c }

переводится как

as >>= (\a -> bs >>= (\b -> foo b >>= (\c -> return c)))

так что это не "начальный", это одна объединенная всеобъемлющая лямбда, которая вызывается с начальным состоянием!

А потом он позвонит

let (a,s1) = runState as s0

и т.д.. с этим «начальным» as в блоке do.

2 голосов
/ 20 мая 2019

блок do не не выполняет никаких вычислений с состоянием - он только собирает некоторые меньшие вычисления с состоянием в одно большее вычисление с состоянием.На уровне do фактическое состояние не существует.

Было бы проще и, возможно, еще точнее, если бы монаду называли «вычислением с состоянием».Или «функция, которая принимает состояние типа S и возвращает другое состояние того же типа наряду с его фактическим результатом».Тогда вы можете представить >>= как «объединяет две функции вышеупомянутого типа в одну, так что состояние, возвращаемое первой, передается как параметр второй».

1 голос
/ 20 мая 2019

State - это просто оболочка для функций типа s -> (a, s). runState на самом деле ничего не «запускает»; он просто возвращает функцию, обернутую конструктором State. Однако вы можете сравнить runState с оператором ($) для функций.

($)             f  x = f x
runState (State f) s = f s

Это делает (=<<) = flip (>>=) похожим на (<<<) = (.); вместо того, чтобы брать две функции и возвращать третью функцию, она берет функцию (которая возвращает State) и State и производит вторую State.

Однако мы сделаем прямое сравнение (>>=) с (>>>) = flip (.), чтобы типы лучше выравнивались. (Точно так же вы можете сравнить (.) с (=<<).)

-- f :: t -> a
-- g ::      a -> b
f >>> g =         \t -> let a       = ($)      f     t
                        in            ($)      g     a
-- m :: State s a
-- g ::         a -> State s b
m >>= g = State $ \s -> let (a, s') = runState m     s
                        in            runState (g a) s'
...