Pure编程语言是apparently based on term rewriting,而不是传统上类似外语的lambda演算。
......这会产生什么质的,实际的差异?事实上,是它评估表达式的方式的差异?
链接页面提供了大量术语重写有用的示例,但它实际上并没有描述它与函数应用程序的不同之处,除了它有相当灵活的模式匹配(和Haskell和ML中出现的模式匹配很好,但不是评估策略的基础)。价值与定义的左侧相匹配,并被替换为右侧 - 这不仅仅是β减少吗?
模式的匹配和输出表达式的替换,表面上看起来有点像syntax-rules
(甚至是简陋的#define
),但其主要特征显然是它发生了<在评估期间之前而不是,而Pure是完全动态的,并且在其评估系统中没有明显的相位分离(事实上,否则Lisp宏系统总是会产生很大的噪音他们如何 与功能应用程序不同)。能够操纵符号表达值是很酷的所有,但也似乎是动态类型系统的工件而不是评估策略的核心(非常确定你可以重载Scheme中的运算符来处理符号值;实际上you can even do it in C++带有表达式模板)。
那么术语重写(由Pure使用)和传统功能应用程序之间的机械/操作差异是什么,作为评估的基础模型,当两者都发生替换时?
答案 0 :(得分:10)
术语重写不必看起来像函数应用程序,但像Pure这样的语言强调这种风格,因为a)beta-reduction很容易定义为重写规则而b)函数式编程是一个很好理解的范例
一个反例可能是黑板或元组空间范式,术语重写也非常适合。
beta-reduction和完全术语重写之间的一个实际区别是重写规则可以对表达式的定义进行操作,而不仅仅是其值。这包括对可简化表达式的模式匹配:
-- 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不等同,因为它不安全或卫生(预处理后,有效的程序可能会失效)。
我们还可以根据需要为现有功能定义ad-hoc子句,例如
plus (times x y) (times x z) = times x (plus y z)
另一个实际考虑因素是,如果我们想要确定性结果,重写规则必须是confluent。无论我们应用规则的顺序如何,我们都得到相同的结果。没有算法可以为我们检查这一点(一般来说它是不可判定的)并且搜索空间太大而不能让个别测试告诉我们太多。相反,我们必须说服自己,我们的系统通过一些正式或非正式的证据来融合;一种方法是遵循已知融合的系统。
例如,已知β减少是汇合的(通过Church-Rosser Theorem),因此如果我们以beta减少的方式编写所有规则,那么我们可以确信我们的规则是汇合的。当然,这正是函数式编程语言的作用!