ContT、callCC、とHaskellの混乱
-
19-09-2019 - |
質問
ContTや友人の意味を理解するためにクエストを継続。下記(不条理が、説明の)コードをご検討くださいます:
v :: IO (Either String [String])
v = return $ Left "Error message"
doit :: IO (Either String ())
doit = (flip runContT return) $ callCC $ \k -> do
x <- liftIO $ v
x2 <- either (k . Left) return x
when True $ k (Left "Error message 2")
-- k (Left "Error message 3")
return $ Right () -- success
このコードはコンパイルされません。その下のコメントk個の呼び出しでwhen
を交換する場合は、それがコンパイルされます。何が起こっているのですか?
あるいは、それはまた、コンパイルされます。 ???
明らかに、これはすべての要素が目的にかなうように蒸留元のコードのバージョンとなります。何が起こっているのかについての説明の助けに感謝し、どのようにそれを修正します。おかげます。
解決
ここでの問題はwhen
とeither
の種類、ないContTに特に何も関係しています:
when :: forall (m :: * -> *). (Monad m) => Bool -> m () -> m ()
either :: forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
二番目の引数には、いくつかのモナドm ()
の型m
であることが必要です。あなたのコードのwhen
ラインは、このようにそのように修正することができます:
when True $ k (Left "Error message 2") >> return ()
コードのコンパイルを行います。これは、あなたが何をしたいのか、おそらくありませんが、それは間違っているかもしれないものへと私たちにヒントを与える:k
のタイプはwhen
にまずいものになると推定されています。
次にeither
署名用:either
に2つの引数が同じタイプの結果を生成する関数でなければならないことに気付きます。 return
の種類は、ここでx
に明示的に署名することによって固定され順番にあるv
の種類によって決定されます。したがって(k . Left)
ビットは、同じ型を持っている必要があります。これは、順番に
k
のタイプを固定します
k :: Either String () -> ContT (Either String ()) IO [String]
このはwhen
の期待と互換性がありません。
あなたはx2
ライン、しかし、コードの型チェッカーのビューに及ぼす影響を除去するコメントアウトないので、k
はもはや不便なタイプに強制さと種類を想定して自由である場合には、
k :: Either [Char] () -> ContT (Either [Char] ()) IO ()
これwhen
の本で結構です。したがって、コードはコンパイルされます。
最後の注意点として、私は2つのシナリオの下でk
の正確な種類を得るために、GHCiののブレークポイント機能を使用する - 私は手でそれらを書き、自分の正しさを保証どのような方法であることに十分な専門家の近くにどこにもよん。 :-)それを試してみること:break ModuleName line-number column-number
を使用します。