如何使用 putStrLn 进行跟踪 (Haskell)
我试图通过添加对“putStrLn”的调用来让 Haskell 函数在应用时显示:(
isPrime2 1 = False
isPrime2 n = do
putStrLn n
null (filter (==0) (map (mod n) (filter isPrime2 [2..(floor (sqrt(fromIntegral (n-1))))])))
最终目标是演示为什么 isPrime 的一个版本比另一个版本更有效。)
当我将上述代码加载到 GHCi 中时,我收到错误:
无法将预期类型
Bool
与实际类型m0 b0
匹配
我确信这是一个严重的错误。有人可以告诉我完成我想做的事情的正确方法吗?
I am trying to get a Haskell function to show whenever it is applied by adding a call to "putStrLn":
isPrime2 1 = False
isPrime2 n = do
putStrLn n
null (filter (==0) (map (mod n) (filter isPrime2 [2..(floor (sqrt(fromIntegral (n-1))))])))
(The ultimate goal is to demonstrate why one version of isPrime is more efficient than another.)
When I load the above code into GHCi, I get the error:
Couldn't match expected type
Bool
with actual typem0 b0
I'm sure this is a n00b mistake. Could someone tell me the right way to accomplish what I'm trying to do?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
问题是,Haskell 对
(+)
和map
等纯函数和不纯有严格的区分诸如putStrLn
和main
之类的操作。当给定相同的输入并且不修改任何内容时,纯函数应该总是产生相同的结果。这显然禁止使用PutStr
和朋友。类型系统实际上强制执行这种分离。每个执行 IO 或以任何方式不纯的函数在其类型前面都有一个 IO 。太长;博士;使用模块
Debug.Trace
中的trace
:但请注意,结果可能会令人惊讶,因为无法保证您的代码会实际运行;跟踪的参数可以运行一次或两次或任何其他次数。
The problem is, that Haskell has a strict distinction between pure functions such as
(+)
andmap
and impure actions such asputStrLn
andmain
. A pure function is supposed to always yield the same result when given the same input and not modifying anything. This obviously prohibits uses ofPutStr
and friends. The type system actually enforces this separation. Each function that does IO or is impure in any way has anIO
sticking in front of it's type.tl;dr; use
trace
from the moduleDebug.Trace
:But beware that the results may be rather surprising as there is no guarantee that your code will actually run; the argument of trace may run once or twice or any other number of times.
每当您遇到此类类型错误(例如
无法将预期类型 X 与实际类型 Y 匹配
)时,您应该使用 haskell 类型系统来指导您。那么让我们看看问题是什么:
您有一个类型为 Int -> 的纯函数。布尔。并且您想要打印一些显然不纯粹的调试输出(即存在于IO Monad中)。
但无论如何,你想写的是……沿着这些思路:
不过,你的函数的类型应该是
foo :: Int -> Bool
因此,让我们定义一个满足类型检查器要求的
debug
函数。它必须接受一个字符串(您的调试消息)和一个布尔值(您的结果),并且仅计算布尔值。但是如果我们尝试实现它,它就不起作用了,因为我们无法转义 IO Monad,因为 putStrLn 的类型是
putStrLn :: String ->; IO()。为了将其与
Bool
的计算结合起来,我们也必须将Bool
放入IO
的上下文中:好的,让我们问一下ghci 表示此函数的类型:
因此我们得到一个
IO Bool
,但只需要一个Bool
。是否有一个类型为 IO b ->; 的函数b?快速查找 hoogle 给我们一个提示
:臭名昭著的
unsafePerformIO :: IO a -> a
具有我们需要的类型。所以现在我们可以根据
debugIO
实现我们的debug
函数:这实际上与
trace
得到的差不多 函数rel="nofollow">Debug.Trace
包,正如 FUZxxl 已经指出的。由于我们同意永远不要使用
unsafePerformIO
,因此首选使用trace
函数。请记住,尽管它是纯类型签名,但它实际上也是不引用透明的,并且在底层使用了unsafePerformIO
。Whenever you have these kinds of type errors like
Couldn't match expected type X with actual type Y
you should use the haskell type system to guide you.So let's see what is the problem:
You have a pure function with the type
Int -> Bool
. And you want to print some debug output which is clearly not pure (i.e. which lives in the IO Monad).But anyway what you want to write is s.th. along those lines:
Still, the type of your function should be
foo :: Int -> Bool
So let's define a
debug
function that will satisfy the type-checker. It would have to take a String (your debug message) and a Bool (your result) and only evaluate to the Bool.But if we try to implement it, it kind of does not work since we can't escape the IO Monad since the type of putStrLn is
putStrLn :: String -> IO ()
. In order to combine it with evaluating to aBool
we will have to put theBool
in the context of theIO
too:Ok, let's ask ghci for the type of this function:
So we get an
IO Bool
but would need just aBool
.Is there a function with the type
IO b -> b
? A quick lookup on hoogle gives us a hint:The infamous
unsafePerformIO :: IO a -> a
has the type we need here.So now we could implement our
debug
function in terms ofdebugIO
:which actually is pretty much what you get with the
trace
function in theDebug.Trace
package as already pointed out by FUZxxl.And since we agree that one should never use
unsafePerformIO
the usage of thetrace
function is preferred. Just keep in mind that despite it's pure type signature it actually is also not referential transparent and usesunsafePerformIO
underneath.