每当您遇到此类类型错误时,Couldn't match expected type X with actual type Y
您都应该使用 haskell 类型系统来指导您。
那么让我们看看有什么问题:
你有一个带有 type 的纯函数Int -> Bool
。并且您想打印一些显然不纯的调试输出(即存在于IO Monad中)。
但无论如何你想写的是s.th。沿着这些思路:
foo x
| x > 0 = debug "ok" True
| otherwise = debug "ohhh...no" False
不过,您的功能类型应该是foo :: Int -> Bool
因此,让我们定义一个debug
满足类型检查器的函数。它必须接受一个字符串(你的调试消息)和一个布尔值(你的结果),并且只计算布尔值。
debug :: String -> Bool -> Bool
debug = undefined
但是如果我们尝试实现它,它就会不起作用,因为我们无法逃脱 IO Monad,因为 putStrLn 的类型是putStrLn :: String -> IO ()
. 为了将它与对 a 的评估结合起来,Bool
我们必须将 theBool
置于 the 的上下文中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