Как вы правильно заметили, монада State используется для передачи некоторого внешнего значения 'state' через ряд вычислений. Однако вы спрашиваете, как это состояние «сохраняется» при множественных вызовах вашей функции addResult :: Integer -> State [String] ()
для каждого значения списка list
. Уловка - определение mapM_
. Начнем с рассмотрения более простой функции mapM
:
mapM f [] = return []
mapM f (x:xs) = do
fx <- f x
fxs <- mapM f xs
return (fx : fxs)
Если мы мысленно «расширим» это рекурсивное определение, скажем, с помощью примера списка [x1,x2,x3,x4,...,xn]
, мы увидим, что значение mapM f [x1,...,xn]
будет другим монадическим вычислением:
do
fx1 <- f x1
fx2 <- f x2
-- etc.
fxn <- f xn
return [fx1,fx2,...,fxn]
Итак, mapM
в основном «склеивает» кучу монадических вычислений в один большой, объединяя их в порядке. Что объясняет, как вы строите список вместо того, чтобы создавать множество меньших: get
в начале addResult
получает состояние с последнего запуска , а не с начала, потому что вы работаете все вычисления вместе, вот так:
do
fl0 <- addResult (list !! 0)
fl1 <- addResult (list !! 1)
-- etc. like before
(Если вы внимательно прочитаете, вы заметите, что я говорил о mapM
, но вы на самом деле использовали mapM_
. Они точно такие же, за исключением того, что последний возвращает ()
.)