42

一些语言,如 Haskell(或 Nemerle)有quasiquotations。我想知道“准”是什么意思,是否也存在没有“准”部分的“引用”。

4

5 回答 5

42

我相信这个概念来自 Lisp 语言。

用 Lisp 编写的程序由一系列列表列表等组成,如下所示:

 (defn f [x y] (+ x y))

由于这种统一性,可以将此类代码表示和操作为数据,因此上述字符序列被解释为文字列表。这是 Lisp 非常有用的特性,也是它们的显着特征之一。为方便起见,Lisp 语言允许“引用”有意义的序列,将它们从定义和表达式转换为列表。它看起来像这样:

 '(defn f [x y] (+ x y))

在这种情况下,它是一个文字列表,可直接用于使用 Haskell 和其他方法的类似物进行head解构tail。因此,“引用”的意思是“从列表中生成文字值”。

但是,直接使用head- 和 -tail类函数操作列表并不方便。当您开始编写复杂的宏甚至是宏生成宏时,这一点就会变得值得注意。所以这里出现了“准引用”,字面意思是“几乎是一个引用”。通常 quasiquotation 看起来像普通引用(但带有另一个引用符号):

`(defn f [x y] (+ x y))

但它是更强大的东西。在 quasiquoted list 中,您可以用外部范围的实际值替换任意元素,基本上获得类似模式的东西。例子:

 (let [z 10] `(defn f [x y] (+ x y ~z)))

在这里,我们将值绑定10z变量,然后我们将其替换为 quasiquote。这个表达式产生

 '(defn f [x y] (+ x y 10))

这是一个简单的例子;Lisp 语言允许使用准引号做许多其他有用的事情。

这个概念已经转移到支持使用语法树进行操作的其他语言。例如,这里的 Haskell 工具是 Template Haskell,它完全支持准引用,即创建模板并用外部范围的值填充它们。在具有复杂语法的语言(如 Haskell)中,准引用和纯引用几乎成为操作语法树的唯一合理方法。

UPD:嗯,似乎在 Haskell 中它比简单的替换更复杂。Haskell 中的 Quasiquote 看起来像可以由用户定义的任意转换器和表达式评估器。

于 2012-05-11T18:38:14.410 回答
19

这些概念存在于 Lisp 语言及其变体中。

在这些语言中,每当解释器看到一个列表(a b c ... z)时,它就会通过应用到其他元素来评估它。ab ... z

如果您不希望对列表进行评估(因此将其解释为列表),则必须引用它。例如,'(a b c)评估为具有三个元素的列表,而不是a应用于band c。您可以将报价视为停止评估

现在 quasiquotation 的行为类似于引用,除了您可以在列表的某些部分内恢复评估。您用后撇号 ` 进行 quasiquote,并且您允许使用逗号运算符不引用某些子表达式至少在 Scheme 中,我不知道其他 Lisp 变体)。例如

`(a ,(b c))

评估为具有两个元素的列表:a和 的评估结果(b c)

这对于构建模板特别有用,您可以通过取消引用来填补漏洞。示例(取自那里):

(define (create-shipping-employee-association name)
  `((name ,name)
    (employee-id-no ,(get-next-employee-id!))
    (department shipping)
    (hire-date ,(get-day) ,(get-month) ,(get-year))))
于 2012-05-11T18:56:47.737 回答
5

在 Nemerle 中,准引用是(http://nemerle.org/metaprogramming.pdf):

"

元语言是一种用于对此类操作进行编程的语言。它通常有自己的语法来描述对象语言的各种结构。

例如,在我们的系统中:

<[ 1 + f (2 * x) ]>

表示表达式的语法树:

1 + f (2 * x)

这个想法被称为准报价。

前缀来自将元语言表达式的值插入引用的上下文的可能性。

ifg(y)是这样一个表达式,我们可以这样写:

<[ 1 + $(g(y)) ]>

它描述了一个语法树,它的第二部分被评估的结果替换g(y)

"

于 2012-05-12T16:58:20.587 回答
2

引号只是一个字符串文字。 引号是“引用”的,因为它们在某种意义上表示输入,而不是编译代码;它们只是以一种更容易从编译过程内部操作的形式来表示它(抽象语法树,您可以通过各种方式移植它,这些方式比在文本上操作更安全)。

于 2012-05-11T18:26:02.163 回答
2

Quasi 基本意思就是可以在引号里面放一个美元符号,然后再切换到不带引号的代码:

<[ WriteLine( $(ReadLine()) ) ]>

这将在运行时输出在编译时输入的字符串(实际上我认为这在 Visual Studio 中不起作用,因为 ReadLine 需要控制台输入;但您可以从文件、网络等读取)。

于 2012-05-13T12:09:39.927 回答