Примечание: ответ camccann лучше моего, но мой использует немного другой подход и дает пример того, как оценивать монаду состояния, поэтому я оставляю его здесь для справки.
Мы можем начать пытаться выяснить проблему, удалив сигнатуру типа для getAverage
и аргумент (c
), который не появляется в функции:
getAverage s=get >>= \s0 -> let (x,s1) =media s s0
in put s1 >> return x
Это все еще не компилируется, потому что мы пытаемся put
что-то, что не имеет правильного типа: s1
это Double
, а не MyState
. Это легко поправимо:
getAverage s=get >>= \s0 -> let s1@(x,_) =media s s0
in put s1 >> return x
Мы также можем оставить шаблон let
без изменений и просто сказать put (x,s1)
: вместо этого я делаю это так, чтобы наш s1
имел тот же тип, что и s0
.
Это компилируется, так что теперь мы можем исправить сигнатуру типа. Если мы запросим у GHCi тип, он вернет следующее:
getAverage :: (Fractional t, MonadState (t, t) m) => t -> m t
Double
— это экземпляр Fractional
, а State MyState
— экземпляр MonadState (Double, Double)
, поэтому мы можем использовать что-то очень похожее на исходный тип для getAverage
:
getAverage :: Double -> State MyState Double
Эта функция на самом деле не «получает» среднее значение: она обновляет его после добавления нового значения, поэтому давайте переименуем его соответствующим образом:
updateAverage :: Double -> State MyState Double
updateAverage s=get >>= \s0 -> let s1@(x,_) =media s s0
in put s1 >> return x
Теперь мы можем определить функцию getAverages
, которая берет список Double
, пропускает их через updateAverage
и возвращает список промежуточных средних значений на каждом шаге:
getAverages :: [Double] -> [Double]
getAverages ss = evalState (mapM updateAverage ss) (0, 0)
Это делает то, что мы ожидаем:
*Main> getAverages [1..10]
[1.0,1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5]
Обратите внимание: чтобы сделать что-нибудь полезное с монадой State
, вам всегда придется использовать evalState
(или тесно связанные runState
и execState
).
person
Travis Brown
schedule
30.07.2010
getAverage
? - person Sam Heather   schedule 13.05.2014