函数式编程的 Monad,2.2 变体一:异常

问题描述 投票:0回答:2

我一直在努力更好地理解 Haskell 中的 Monad,因此我开始阅读 Philip Wadler 的论文 Monads for function 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”,并得出结论,也许我需要为 M a 添加一个实例。但是当我添加

instance Show (M a) where
show (M a) = show a

对于我的代码,我尝试重新加载文件,但出现此错误。

Not in scope: data constructor ‘M’

这起初让我感到困惑,但this帖子解释说我正在定义类型构造函数而不是数据构造函数。

无论如何,我觉得我正在掉入一个兔子洞,可能有也可能没有解决方案,我想我应该在这里发布问题。我的代码看起来与他的代码逐行相同。我需要进行哪些更改才能使代码在 GHCi 中运行?

haskell monads
2个回答
5
投票

添加的

Show
实例将无法工作,原因有两个:

  1. 没有任何约束表明
    a
    M a
    Show
    的实例;和
  2. M
    数据类型没有数据构造函数
    M
    ,它有一个
    Raise
    和一个
    Return

因此,一个简单的实现如下所示:

instance Show a => Show (M a) where
    show (Raise a) = "Raise " ++ show a
    show (Return a) = "Return " ++ show a

但是我们可以省去这个麻烦,让 Haskell 自动派生出

Show
的实例:

data M a = Raise Exception | Return a deriving Show

3
投票

如果您想手动执行此操作,则必须执行以下操作

instance (Show a) => Show (M a) where
    show (Raise e)  = "Raise " ++ show e
    show (Return a) = "Return " ++ show a

您的类型 (

M a
) 有两个数据构造函数,
Raise
Return

最简单的解决方案就是直接说

data M a = Raise Exception | Return a
    deriving (Show)

或者,您也可以在每次想要在 ghci 中检查

M a
值时手动解构它们:

case eval answer of { Raise e -> "An error occurred: " ++ e; Return x -> show x }
-- instead of 'eval answer'

但这很快就会变得烦人。

© www.soinside.com 2019 - 2024. All rights reserved.