Я изначально собирался опубликовать это как комментарий, но решил изложить немного больше.
Строго говоря, get
не «принимает» аргумент. Я думаю, что многое из того, что происходит, замаскировано тем, что вы не видите, - определениями экземпляров государственной монады.
get
на самом деле является методом класса MonadState. Государство монада является экземпляром MonadState, обеспечивая следующее определение get
:
get = State $ \s -> (s,s)
Другими словами, get
просто возвращает очень простой State монады (напомним, что монада можно рассматривать как «обертки» для вычисление), где любой ввод s
в вычисление возвращает в результате пару s
.
Следующая вещь, которую мы должны смотреть на это >>=
, что государство определяет таким образом:
m >>= k = State $ \s -> let
(a, s') = runState m s
in runState (k a) s'
Так, >>=
собирается дать новое вычисление, которое не будет вычисляться до тех пор, пока он получает начальное состояние (это справедливо для всех государственных вычислений, когда они находятся в их «завернутой» форме). Результат этого нового вычисления достигается, применяя все, что находится справа от >>=
, к результату выполнения вычисления, которое было с левой стороны.(Это довольно запутанное предложение, которое может потребовать дополнительного чтения или два.)
Я нашел весьма полезным для "desugar" все, что происходит. Для этого требуется гораздо больше ввода текста, но вы должны ответить на свой вопрос (откуда get
) очень ясно. Обратите внимание, что следует учитывать следующее psuedocode ...
test x =
State $ \s -> let
(a,s') = runState (State (\s -> (s,s))) s --substituting above defn. of 'get'
in runState (rightSide a) s'
where
rightSide test =
let test' = x ++ test in
State $ \s2 -> let
(a2, s2') = runState (State $ \_ -> ((), test')) s2 -- defn. of 'put'
in runState (rightSide2 a2) s2'
rightSide2 _ =
-- etc...
Это должно сделать это очевидным, что конечный результат нашей функции является новым государством вычисление, которое потребуется начальное значение (s
), чтобы сделать остальную часть вещи случаются. Вы поставили s
как "testtest"
с вашим звонком runState
. Если вы замените «testtest» на s
в вышеуказанном псевдокоде, вы увидите, что первое, что происходит, - это запустить get
с «testtest» в качестве «начального состояния». Это дает ("testtest", "testtest")
и так далее.
Так вот где get
получает ваше первоначальное состояние «testtest». Надеюсь это поможет!
Я не мог придумать лучшего слова, когда сказал, что «принял» аргумент. Спасибо за это очень подробное объяснение. – Rayne