亲爱的 StackExchange 专家,
我一直在尝试从《使用 Haskell 进行编程》一书中学习如何在 Haskell 中编程,并且我在第 5 章中遇到了一个涉及闭包的示例。我尝试按如下方式实现它:
ifEven func x = if even x then func x else x
genIfEven x = (\func -> ifEven func x)
testfunc1 :: Num a => a -> a
testfunc1 x = x+2
main = do{
genIfEven 3 testfunc1
}
不幸的是,虽然这是书中的一个例子,但由于我什至还不明白的打字原因(
No instance for (Integral (IO t0)) arising from a use of ‘genIfEven’
),编译器一直拒绝它。
有没有人可以向我解释我做错了什么,并向我指出如何修复此代码以使其正常工作? :)
如果你这样写,你会得到大致相同的错误:
main = 3
您的所有其余代码都只是隐藏了这个核心问题,所以我将解释为什么这是不正确的以及编译器如何尝试向您解释这一点。
为什么它不正确的简短答案是:它不执行任何 IO(甚至不执行从
pure
/return
获得的无所事事的 IO)。您的 main
需要做一些 IO
。您可以通过编写来解决此问题,例如,
main = pure 3
-- OR
main = print 3
但是简短的答案不太正确,因为如果
3
的类型不是 IO _
,那么它是什么?问问ghci:
> :t 3
3 :: Num a => a
3
并不存在真正单一、简单的类型!任何具有 Num
类型类实例的类型都是合理的。在标准库中,这些类型包括 Int
、Integer
、Word16
、Double
等。
问题是:为 Num
操作声明
IO
实例是合法(尽管由于多种原因很少见)!在这种情况下,
main = 3
毕竟是一个有效的程序。所以类型不匹配是潜在的。返回您的确切错误:
No instance for (Integral (IO t0)) arising from a use of ‘genIfEven’
这是使用
Integral
类,而不是 Num
类(因为你使用了 even
),但核心思想本质上是相同的:如果只有 Integral
动作有一个 IO
实例,你的程序将是合法的。但没有,所以不是。