注: 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関数を定義できます。DoubleupdateAverage
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(または密接に関連するrunStateand ) を常に使用する必要があることに注意してくださいexecState。