术语重写不必看起来像函数应用程序,但是像 Pure 这样的语言强调这种风格,因为 a) beta-reduction 很容易定义为重写规则,b) 函数式编程是一种易于理解的范例。
一个反例是黑板或元组空间范式,术语重写也非常适合。
beta-reduction 和 full-term-rewriting 之间的一个实际区别是,重写规则可以对表达式的定义进行操作,而不仅仅是它的值。这包括对可约表达式的模式匹配:
-- Functional style
map f nil = nil
map f (cons x xs) = cons (f x) (map f xs)
-- Compose f and g before mapping, to prevent traversing xs twice
result = map (compose f g) xs
-- Term-rewriting style: spot double-maps before they're reduced
map f (map g xs) = map (compose f g) xs
map f nil = nil
map f (cons x xs) = cons (f x) (map f xs)
-- All double maps are now automatically fused
result = map f (map g xs)
请注意,我们可以使用 LISP 宏(或 C++ 模板)来做到这一点,因为它们是一个术语重写系统,但这种风格模糊了 LISP 对宏和函数的清晰区分。
CPP 的 #define 不等效,因为它不安全或不卫生(语法上有效的程序在预处理后可能变得无效)。
我们还可以根据需要为现有函数定义临时子句,例如。
plus (times x y) (times x z) = times x (plus y z)
另一个实际考虑是,如果我们想要确定性的结果,重写规则必须是汇合的,即。无论我们应用规则的顺序如何,我们都会得到相同的结果。没有算法可以为我们检查这一点(通常无法确定),并且搜索空间太大,单个测试无法告诉我们太多信息。相反,我们必须通过一些正式或非正式的证明来说服自己,我们的系统是融合的;一种方法是遵循已知的融合系统。
例如,已知 beta-reduction 是合流的(通过Church-Rosser 定理),所以如果我们以 beta-reduction 的方式编写所有规则,那么我们可以确信我们的规则是合流的。当然,这正是函数式编程语言所做的!