注: 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
and ) を常に使用する必要があることに注意してくださいexecState
。