Haskell の ST モナドを使った破壊的な処理で、処理の一部分を外から渡せるようにしようとしています。
たとえば下記の printSum1
では全ての処理をハードコードしています。これを printSum3
のように、一部の処理を引数で与えるようにしたいのですが、printSum3
は proc
を評価する行で型エラーになってしまいます。
printSum2
のように、引数を取っても使わなければエラーにならないようです。
エラーを見たところでは、ST s ()
と ST s1 ()
という異なる型になっていて、互換性がないということのようですが…なぜそうなるのでしょうか?
printSum3
を通す方法はありますか?
よろしくお願いします。
import Control.Monad.ST
import Data.STRef
add10 :: STRef s Int -> ST s ()
add10 r = modifySTRef r (+ 10)
-- add10 をハードコードする
printSum1 :: IO ()
printSum1 =
print sum
where
sum :: Int
sum = runST $ do
r <- newSTRef 0
modifySTRef r (+ 1)
modifySTRef r (+ 1)
add10 r -- ★
readSTRef r
-- 関数を外から受け取るが、使わない
printSum2 :: (STRef s Int -> ST s ()) -> IO ()
printSum2 proc =
print sum
where
sum :: Int
sum = runST $ do
r <- newSTRef 0
modifySTRef r (+ 1)
modifySTRef r (+ 1)
add10 r -- ★
readSTRef r
-- 外から受け取った関数を使う……これだけが型エラーになる
printSum3 :: (STRef s Int -> ST s ()) -> IO ()
printSum3 proc =
print sum
where
sum :: Int
sum = runST $ do
r <- newSTRef 0
modifySTRef r (+ 1)
modifySTRef r (+ 1)
proc r -- ★
readSTRef r
main = do
printSum1
printSum2 add10
printSum3 add10
exper\st.hs:43:25:
Couldn't match type `s' with `s1'
`s' is a rigid type variable bound by
the type signature for
printSum3 :: (STRef s Int -> ST s ()) -> IO ()
at exper\st.hs:34:14
`s1' is a rigid type variable bound by
a type expected by the context: ST s1 Int at exper\st.hs:39:23
Expected type: ST s1 ()
Actual type: ST s ()
In the return type of a call of `proc'
In a stmt of a 'do' block: proc r
In the second argument of `($)', namely
`do { r <- newSTRef 0;
modifySTRef r (+ 1);
modifySTRef r (+ 1);
proc r;
.... }'