在模式匹配中首先强制评估?

Forcing evaluation first in a pattern match?

我想在对传递给函数的数据构造函数内的参数求值后,将函数重新运行返回模式。例如

func (Plus a b) = func (Plus (func a) (func b))

注意afunc a是同一类型。当我尝试调用这样的东西时,程序挂断了,我认为正在发生的事情是模式在评估内部 (func a)(func b) 之前无限期地与自身匹配,否则会匹配它到不同的模式。我试过使用类似

的东西
func (Plus a b) = func (Plus newa newb)
    where newa = func a
          newb = func b

尝试强制首先计算 func afunc b,但这不起作用。我正在尝试做的事情是否可行?

谢谢。

你确实进入了一个循环,你一遍又一遍地匹配 Plus,但你期望什么?

func (Plus a b)
   = func (Plus (func a) (func b))
   = func (Plus (func (func a)) (func (func b)))
   = func (Plus (func (func (func a))) (func (func (func b))))

问题是你实际上是在说,"to evaluate func on a Plus constructor, evaluate func on a Plus constructor"。

func 的其余部分是什么样子的?如果整个定义类似于:

,原则上您的方法可以工作
func (Plus (Lit n) (Lit m)) = Lit (n + m)
func (Plus a b) = func (Plus (func a) (func b))

这里如果 func afunc b 最终减少到 Lit,那么第一个模式将匹配并且调用将终止。但是我会犹豫这样写一个函数,因为你怎么知道在一个参数上重复调用 func 最终会收敛到 Lit?很可能会有不会的情况。


我怀疑你在写一个符号求值器。更好的方法是为表达式想出一个 正常形式 ,然后让你的 reducer 减少到正常形式。范式是一种独特的表示形式,您始终可以将表达式简化为。有时需要一些技巧才能想出一个好的范式。但是假设你的表达类型是:

data Expr = Lit Int | Var String | Plus Expr Expr

为此,示例范式可能是:

data ExprNF = ExprNF Int [String]

表示一个常量加上按排序顺序排列的变量之和(保持排序以便等价表达式总是比较相等)。所以如果你的表达是

1 + (x + 2) + (3 + 6) + (x + (y + x))

它将成为正常形式:

ExprNF 10 ["x","x","x","y"]

你的 reducer func :: Expr -> ExprNF 递归地计算范式,没有必要重复调用它以期收敛。

func :: Expr -> ExprNF
func (Lit n) = ExprNF n []
func (Var s) = ExprNF 0 [s]
func (Plus a b) = case (func a, func b) of
    (ExprNF n vs, ExprNF n' vs') -> ExprNF (n + n') (sort (vs ++ vs'))

我们永远不必多次减少树中的任何节点,因为我们会立即得到一个正常形式。