Первоначально я собирался опубликовать это в качестве комментария, но решил изложить немного больше.
Строго говоря, get
не "принимает" аргумент. Я думаю, что многое из того, что происходит, маскируется тем, чего вы не видите - определениями экземпляров Государственной монады.
get
на самом деле является методом класса MonadState. Монада State является экземпляром 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'
Итак, >>=
даст новое вычисление, которое не будет вычислено, пока не получит начальное состояние (это верно для всех вычислений состояний, когда они находятся в «обернутой» форме). Результат этого нового вычисления достигается путем применения того, что находится справа от >>=
к результату выполнения вычисления, которое было слева. (Это довольно запутанное предложение, которое может потребовать дополнительного чтения или двух.)
Мне показалось весьма полезным "десугарировать" все, что происходит. Это займет намного больше времени, но ответ на ваш вопрос (откуда берется 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". Надеюсь, это поможет!