Haskell の ST モナドを使った破壊的な処理で、処理の一部分を外から渡せるようにしようとしています。
たとえば下記の printSum1 では全ての処理をハードコードしています。これを printSum3 のように、一部の処理を引数で与えるようにしたいのですが、printSum3proc を評価する行で型エラーになってしまいます。
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;
            .... }'