【发布时间】:2018-08-28 06:11:22
【问题描述】:
我一直在努力更好地理解 Haskell 中的 Monad,因此我开始阅读 Philip Wadler 的论文 Monads for functional programming。为了更好地内化这些原则,并让自己尽可能多地接触 Haskell 代码,我决定在阅读论文时编写代码并测试所有示例。
马上2.2 变体一:例外 给我带来了一些麻烦。这是我的代码。
data Term = Con Int | Div Term Term
data M a = Raise Exception | Return a
type Exception = String
answer, error_ :: Term
answer = (Div (Div (Con 1972) (Con 2)) (Con 23))
error_ = (Div (Con 1) (Con 0))
eval :: Term -> M Int
eval (Con a) = Return a
eval (Div t u) = case eval t of
Raise e -> Raise e
Return a ->
case eval u of
Raise e -> Raise e
Return b ->
if b == 0
then Raise "divide by zero"
else Return (a `div` b)
我可以将代码加载到 GHCi 中,但是当我尝试运行时
eval answer
它会抛出错误
No instance for (Show (M Int)) arising from a use of ‘print’
In a stmt of an interactive GHCi command: print it
我阅读了this 帖子,其中解释了为什么调用“print”并得出结论,也许我需要为 Show for M a 添加一个实例。但是当我添加
instance Show (M a) where
show (M a) = show a
对于我的代码,我尝试重新加载文件时出现此错误。
Not in scope: data constructor ‘M’
起初这让我很困惑,但 this 帖子解释说我定义的是类型构造函数而不是数据构造函数。
无论如何,我觉得我正在陷入一个可能有也可能没有解决方案的兔子洞,我想我会在这里发布问题。我的代码看起来与他的代码逐行相同。我需要进行哪些更改才能使代码在 GHCi 中运行?
【问题讨论】:
-
没有数据构造函数
M,只有Raise和Return,所以你需要实现这两种情况。 -
使用
deriving机制的另一个原因——除了节省编写代码——是Haskell 将生成一个正确处理数据优先级和嵌套的实例。所以像show (Return (Con 4))这样的东西会正确地产生字符串"Return (Con 4)"而不是"Return Con 4"(假设Term有一个正确的Show实例)。
标签: haskell