Примечание: ответ от компании camcann лучше, чем у меня, но мой принимает несколько иной подход и дает пример того, как оценить государственную монаду, поэтому я оставляю ее здесь для справки.
Мы можем начать пытаться выяснить эту проблему путем удаления сигнатуры типа для 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 [email protected](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 [email protected](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
).
Вы должны вставить ошибку. –
Что вы вводите в свою командную строку для запуска этой функции 'getAverage'? –