如何使用 putStrLn 进行跟踪 (Haskell)

发布于 2024-12-07 21:20:13 字数 435 浏览 1 评论 0原文

我试图通过添加对“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 type m0 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

穿透光 2024-12-14 21:20:13

问题是,Haskell 对 (+)map函数和不纯有严格的区分诸如 putStrLnmain 之类的操作。当给定相同的输入并且不修改任何内容时,纯函数应该总是产生相同的结果。这显然禁止使用 PutStr 和朋友。类型系统实际上强制执行这种分离。每个执行 IO 或以任何方式不纯的函数在其类型前面都有一个 IO 。


太长;博士;使用模块 Debug.Trace 中的 trace

import Debug.Trace

isPrime2 1 = False
isPrime2 n = show n `trace` null (filter (==0) (map (mod n) (filter isPrime2 [2..(floor (sqrt(fromIntegral (n-1))))])))

但请注意,结果可能会令人惊讶,因为无法保证您的代码会实际运行;跟踪的参数可以运行一次或两次或任何其他次数。

The problem is, that Haskell has a strict distinction between pure functions such as (+) and map and impure actions such as putStrLn and main. A pure function is supposed to always yield the same result when given the same input and not modifying anything. This obviously prohibits uses of PutStr and friends. The type system actually enforces this separation. Each function that does IO or is impure in any way has an IO sticking in front of it's type.


tl;dr; use trace from the module Debug.Trace:

import Debug.Trace

isPrime2 1 = False
isPrime2 n = show n `trace` null (filter (==0) (map (mod n) (filter isPrime2 [2..(floor (sqrt(fromIntegral (n-1))))])))

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.

九八野马 2024-12-14 21:20:13

每当您遇到此类类型错误(例如 无法将预期类型 X 与实际类型 Y 匹配)时,您应该使用 haskell 类型系统来指导您。
那么让我们看看问题是什么:

您有一个类型为 Int -> 的纯函数。布尔。并且您想要打印一些显然不纯粹的调试输出(即存在于IO Monad中)。
但无论如何,你想写的是……沿着这些思路:

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()。为了将其与 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 具有我们需要的类型。
所以现在我们可以根据debugIO实现我们的debug函数:

debug :: String -> Bool -> Bool
debug s r = unsafePerformIO $ debugIO s r

这实际上与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:

foo x 
  | x > 0 = debug "ok" True
  | otherwise = debug "ohhh...no" False

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.

debug :: String -> Bool -> Bool
debug = undefined

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 a Bool we will have to put the Bool in the context of the IO too:

debugIO msg result = putStrLn msg >> return result

Ok, let's ask ghci for the type of this function:

Main> :t debugIO
debugIO :: String -> b -> IO b

So we get an IO Bool but would need just a Bool.
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 of debugIO:

debug :: String -> Bool -> Bool
debug s r = unsafePerformIO $ debugIO s r

which actually is pretty much what you get with the trace function in the Debug.Trace package as already pointed out by FUZxxl.
And since we agree that one should never use unsafePerformIO the usage of the trace function is preferred. Just keep in mind that despite it's pure type signature it actually is also not referential transparent and uses unsafePerformIO underneath.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文