quasiquotations中“quasi”的含义是什么?

时间:2012-05-11 18:22:17

标签: haskell programming-languages metaprogramming quoting nemerle

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

5 个答案:

答案 0 :(得分:41)

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

用Lisp编写的程序包含一系列列表列表等,如下所示:

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

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

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

在这种情况下,它是一个文字列表,可直接用于使用Haskell headtail的类似物以及其他方法进行解构。因此,'quote'的意思是'从列表中创建一个字面值'。

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

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

但它更强大。在quasiquoted列表中,您可以使用外部作用域中的实际值替换任意元素,从而基本上获得类似模式的内容。例如:

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

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

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

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

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

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

答案 1 :(得分:19)

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

在这些语言中,只要解释器​​看到列表(a b c ... z),它就会评估,将a应用于其他元素b ... z

如果您想要一个不被评估的列表(因此被解释为一个列表),您必须引用它。例如,'(a b c)评估为包含三个元素的列表,而不是a应用于bc的列表。您可以将报价视为停止评估

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

`(a ,(b c))

评估为包含两个元素的列表:a,以及(b c)的评估结果。

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

(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))))

答案 2 :(得分:5)

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

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

例如,在我们的系统中:

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

表示表达式的语法树:

1 + f (2 * x)

这个想法被称为准引用。

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

如果g(y)是这样的表达式,我们可以写:

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

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

答案 3 :(得分:2)

引文只是一个字符串文字。 引用是指“引用”,它们在某种意义上代表输入而不是编译代码;它们只是以一种更容易在编译过程中进行操作的形式表示它(一种抽象语法树,你可以用各种方式来嫁接,比操作文本更安全)。

答案 4 :(得分:2)

准基本上意味着您可以在引号内放置一个美元符号,然后再次切换到非引用代码:

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

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