このような型エラーが発生Couldn't match expected type X with actual type Y
した場合は、haskell 型システムを使用してガイドする必要があります。
それでは、何が問題なのか見てみましょう。
タイプ の純粋な関数がありInt -> Bool
ます。そして、明らかに純粋ではない(つまりIO Monadに存在する)デバッグ出力を出力したいとします。
とにかく、あなたが書きたいのはs.thです。それらの線に沿って:
foo x
| x > 0 = debug "ok" True
| otherwise = debug "ohhh...no" False
それでも、関数のタイプはfoo :: Int -> Bool
debug
それでは、型チェッカーを満たす関数を定義しましょう。String (デバッグ メッセージ) と Bool (結果) を受け取り、Bool にのみ評価する必要があります。
debug :: String -> Bool -> Bool
debug = undefined
しかし、それを実装しようとすると、 putStrLn の型が であるため IO モナドをエスケープできないため、機能しませんputStrLn :: String -> IO ()
。それを a への評価と組み合わせるには、 the ものコンテキストにBool
入れる必要があります。Bool
IO
debugIO msg result = putStrLn msg >> return result
では、この関数の型を ghci に聞いてみましょう:
Main> :t debugIO
debugIO :: String -> b -> IO b
したがって、 を取得しますIO Bool
が、必要なのはBool
.
タイプの関数はありIO b -> b
ますか?hoogleで簡単に調べると、ヒントが得られます。
悪名高いunsafePerformIO :: IO a -> a
には、ここで必要なタイプがあります。
これで、関数を次のように実装できます。debug
debugIO
debug :: String -> Bool -> Bool
debug s r = unsafePerformIO $ debugIO s r
これは実際には、FUZxxl によって既に指摘されているようtrace
に、パッケージ内の関数で得られるものとほぼ同じです。そして、関数の使用法を決して使用してはならないこと
に同意するので、優先されます。純粋な型シグネチャであるにもかかわらず、実際には参照透過ではなく、その下で使用されることに注意してください。Debug.Trace
unsafePerformIO
trace
unsafePerformIO