在模式匹配中首先强制评估?
Forcing evaluation first in a pattern match?
我想在对传递给函数的数据构造函数内的参数求值后,将函数重新运行返回模式。例如
func (Plus a b) = func (Plus (func a) (func b))
注意a
和func a
是同一类型。当我尝试调用这样的东西时,程序挂断了,我认为正在发生的事情是模式在评估内部 (func a)
和 (func b)
之前无限期地与自身匹配,否则会匹配它到不同的模式。我试过使用类似
的东西
func (Plus a b) = func (Plus newa newb)
where newa = func a
newb = func b
尝试强制首先计算 func a
和 func 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 a
和 func 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'))
我们永远不必多次减少树中的任何节点,因为我们会立即得到一个正常形式。
我想在对传递给函数的数据构造函数内的参数求值后,将函数重新运行返回模式。例如
func (Plus a b) = func (Plus (func a) (func b))
注意a
和func a
是同一类型。当我尝试调用这样的东西时,程序挂断了,我认为正在发生的事情是模式在评估内部 (func a)
和 (func b)
之前无限期地与自身匹配,否则会匹配它到不同的模式。我试过使用类似
func (Plus a b) = func (Plus newa newb)
where newa = func a
newb = func b
尝试强制首先计算 func a
和 func 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 a
和 func 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'))
我们永远不必多次减少树中的任何节点,因为我们会立即得到一个正常形式。