评论中的讨论似乎有点脱轨。无论如何,我对此有不同的看法,所以让我提供一个答案。
我会说 Haskell 已经有一个类似于反引号的功能,并且您可能已经在您自己的 Haskell 编程中广泛使用它而没有意识到它。
您已经在 Lisp 列表和 Haskell 列表之间进行了类比,但在 Lisp 中,S 表达式(即“原子对”,尤其是原子符号)是一种灵活且普遍存在的数据结构,不仅用于表示 Lisp 代码,而且作为首选表示,这至少是任何复杂的结构化数据的首要考虑因素。因此,大多数 Lisp 程序花费大量时间生成和操作这些结构,因此 S 表达式“文字”在 Lisp 代码中很常见。并且,需要计算一些子表达式的 S 表达式“几乎是文字”,使用反引号机制编写比尝试使用更小的文字构建表达式和使用诸如cons
, list
,append
等函数的评估片段更方便。
与 Haskell 相比——Haskell 列表在 Haskell 代码中肯定很流行,并且是表示同质序列的首选结构,但它们仅提供 S 表达式灵活性的一小部分。相反,Haskell 中相应的普遍存在的数据结构是代数数据类型 (ADT)。
好吧,就像 Lisp 的 S 表达式一样,Haskell 程序花费大量时间生成和操作 ADT,而且 Haskell 还为 ADT 文字和“几乎文字”提供了方便的语法。它们被统一为一个单一的“函数应用程序”语法,其中文字和评估部分通过使用构造函数(具有初始大写字母的标识符或以冒号开头的中缀运算符)与非构造函数(具有初始小写字母或中缀的标识符)进行区分没有初始冒号的运算符)。当然,某些构造函数(列表和元组)还有一些额外的语法。
例如,比较 Lisp 和 Haskell 中的以下反引号表达式:
;; Lisp
(setq baz `(node ,id
(node ,(+ id 1) ,left-tree leaf)
(node ,(+ id 2) leaf ,right-tree)))
-- Haskell
baz = Node id (Node (id + 1) left_tree Leaf) (Node (id + 2) Leaf right_tree)
在这个“几乎是字面的”的 Haskell 版本中,Node
和Leaf
构造函数代表引用的部分;、和中left-tree
缀表达式表示被评估的部分,它们在语法上可以通过构造函数和非构造函数的常用规则进行区分。right-tree
+
当然,与此完全不同的是,有一个 Template Haskell 机制,可以在编译时直接操作 Haskell 代码片段。虽然代码表示为 ADT,原则上可以使用与其他 ADT 相同的“几乎字面”语法编写,但所讨论的 ADT 非常麻烦,看起来与底层的 Haskell 代码完全不同。因此,Template Haskell 提供了一种更经典的反引号语法。