4

在某些 lisp(例如elispcommon lisp)中,有一个称为反引号的功能。

它允许在评估或拼接一些元素的同时构造一个列表。例如:

 `(1 2 (3 (+ 4 5))) 
  ⇒ (1 2 (3 (+ 4 5)))  ; just quoted unevaluated list

 `(1 2 (3 ,(+ 4 5)))
  ⇒ (1 2 (3 9))     ; (+ 4 5) has been evaluated

 `(1 2 ,@(list 3 (+ 4 5)))
  ⇒ (1 2 3 9)       ; (3 9) has been spliced into the list

我想,在 Haskell 中,反引用的一些子集可能如下所示:

 [backquote| 1, 2, @$(replicate 2 3), 2 + 2 |]
 ⇒ [1, 2, 3, 3, 4]

我想知道,是否可以像这样拼接到列表中,是否已经实现。

4

1 回答 1

3

评论中的讨论似乎有点脱轨。无论如何,我对此有不同的看法,所以让我提供一个答案。

我会说 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 版本中,NodeLeaf构造函数代表引用的部分;、和中left-tree缀表达式表示被评估的部分,它们在语法上可以通过构造函数和非构造函数的常用规则进行区分。right-tree+

当然,与此完全不同的是,有一个 Template Haskell 机制,可以在编译时直接操作 Haskell 代码片段。虽然代码表示为 ADT,原则上可以使用与其他 ADT 相同的“几乎字面”语法编写,但所讨论的 ADT 非常麻烦,看起来与底层的 Haskell 代码完全不同。因此,Template Haskell 提供了一种更经典的反引号语法。

于 2019-04-25T13:26:34.873 回答