Я думаю, тебя смущает
(x, g') <- return $ random g
Это действительно создает новое монадическое действие State StdGen (a, StdGen)
, которое выполняется для извлечения его результата (a, StdGen)
.
Путаница возникает не без оснований, потому что код фактически эквивалентен
let (x, g') = random g
где не создается монадическое действие, что приводит к более прямому коду. Это преобразование верно для любой монады, а не только для State
.
Во всяком случае, техническая часть: фрагмент (x, g') <- return $ random g
означает
(x, g') <- State (\g'' -> (random g, g''))
где мы можем видеть, что монадическое действие принимает текущее состояние g''
(которое имеет то же значение, что и g), а затем не изменяет его (часть (..., g'')
), возвращая вместе с ним сгенерированное значение random g
(часть (random g, ...)
).
Это немного глупо, поскольку нам даже не нужно читать g''
, поскольку мы используем random g
!
Итак, мы используем
do g <- State (\g'' -> (g'', g''))
(x, g') <- State (\g'' -> (random g, g''))
...
когда мы могли бы вместо этого использовать
do (x, g') <- State (\g'' -> (random g'', g''))
...
который вызывается в библиотеке
do (x, g') <- gets random
...
Ладно, похоже, что путаница в do put g' ; return x
. Это сокращается в связной нотации следующим образом
{ definitions }
put g' = State $ \s -> ((), g')
return x = State $ \s -> (x , s )
do put g ; return x
= { definitions, desugaring }
(State $ \s -> ((), g'))
>>=
(\_ -> State $ \s -> (x , s ))
= { definition of >>= }
State $ \s -> let (v,s') = (\s -> ((), g')) s
in runState ((\_ -> State $ \s -> (x , s )) v) s'
= { beta-reduction (application) }
State $ \s -> let (v,s') = ((), g')
in runState (State $ \s -> (x , s )) s'
= { beta-reduction (let) }
State $ \s -> runState (State $ \s -> (x , s )) g'
= { runState (State y) = y }
State $ \s -> (\s -> (x , s )) g'
= { beta-reduction }
State $ \s -> (x , g')
Таким образом, эффект do put g' ; return x
заключается в изменении состояния на g'
(перезапись предыдущего s
) и выдаче x
в качестве окончательного значения вычисления (вместе с g'
).
person
chi
schedule
19.06.2016
put g'
иreturn x
.return x
следует создать новый экземпляр безg'
, верно? Тогда гдеg'
? Может я неправильно понимаю, что делаетreturn
в do-нотации? Я думал, что это просто реализацияreturn
стратегии монады. - person Gherman   schedule 19.06.2016State StdGen a
представляет вычисление со значением состояния типаStdGen
. Просто представьте, что существует изменяемая переменная императивного стиля типаStdGen
, которую можно читать с помощью действияget
и записывать с помощью действияput x
(x
- новое значение).(x,g') <- return $ random g
- это ИМХО антипаттерн, который лучше всего написаноlet (x,g') = random g
. - person chi   schedule 19.06.2016