是否可以在Haskell函数中调试模式匹配?

qua*_*dev 8 debugging haskell pattern-matching

我已经定义了一种类型

data Expr = 
    Const Double
    | Add Expr Expr
    | Sub Expr Expr
Run Code Online (Sandbox Code Playgroud)

并将其声明为Eq类型类的实例:

instance Eq Expr where
    (Add (Const a1) (Const a2)) == Const b = a1+a2 == b
    (Add (Const a1) (Const a2)) == (Add (Const b1) (Const b2)) = a1+a2 == b1 + b2
Run Code Online (Sandbox Code Playgroud)

当然,表达式的评估Sub (Const 1) (Const 1) == Const 0将失败.如何在运行时调试模式匹配过程以发现它失败?我想看看Haskell如何获取参数==并遍历模式.有可能吗?

Joh*_*n L 3

编辑:提供问题的真实答案......

我发现查看模式匹配的最简单方法是添加trace语句,如下所示:

import Debug.Trace

instance Eq Expr where
    (Add (Const a1) (Const a2)) == Const b = trace "Expr Eq pat 1" $ a1+a2 == b
    (Add (Const a1) (Const a2)) == (Add (Const b1) (Const b2)) = trace "Expr Eq pat 2" $ a1+a2 == b1 + b2
    -- catch any unmatched patterns
    l == r = error $ "Expr Eq failed pattern match. \n l: " ++ show l ++ "\n r: " ++ show r
Run Code Online (Sandbox Code Playgroud)

如果您不包含最终语句来捕获任何其他不匹配的模式,您将收到运行时异常,但我发现查看您获得的数据更有用。然后通常很容易看出为什么它与之前的模式不匹配。

当然,您不想将其留在生产代码中。我只根据需要插入痕迹,然后在完成后将其删除。您还可以使用 CPP 将它们排除在生产版本之外。

我还想说,我认为模式匹配是解决这个问题的错误方法。您最终会遇到模式数量的组合爆炸,这很快就会变得难以管理。例如,如果您想创建一个Float实例Expr,则需要几个更原始的构造函数。

相反,您可能有一个解释器函数interpret :: Expr -> Double,或者至少可以编写一个。然后你可以定义

instance Eq Expr where
  l == r = interpret l == interpret r
Run Code Online (Sandbox Code Playgroud)

通过模式匹配,您实际上是在实例中重写您的解释函数Eq。如果你想创建一个Ord实例,你最终将再次重写解释函数。