实际应用中的报价用途

3
我遇到了“引用”这个术语,我正在尝试找出一些实际应用的例子。每个代码表达式都有AST的能力听起来很棒,但如何在现实生活中使用它呢?
有人知道这样的例子吗?

你可能会发现我的博客文章:关于 F# 引用的注释 很有用。 - Yin Zhu
5个回答

5

F#和Nemerle引用都用于元编程,但方法不同:Nemerle在编译时使用元编程来扩展语言,而F#在运行时使用。

Nemerle

在Nemerle中,引用用于宏内部,以拆解代码并生成新的代码。许多语言本身就是这样实现的。例如,这是一个来自官方库的示例 - 实现when条件构造的宏。Nemerle没有语句,因此if必须有else部分:whenunless宏为一个没有thenelse部分的if提供了简写。 when宏还具有扩展的模式匹配功能。

macro whenmacro (cond, body)
syntax ("when", "(", cond, ")", body)
{
    match (cond)
    {
    | <[ $subCond is $pattern ]> with guard = null
    | <[ $subCond is $pattern when $guard ]> =>
        match (pattern)
        {
        | PT.PExpr.Call when guard != null =>
            // generate expression to replace 'when (expr is call when guard) body'
            <[ match ($subCond) { | $pattern when $guard => $body : void | _ => () } ]>
        | PT.PExpr.Call =>
            // generate expression to replace 'when (expr is call) body'
            <[ match ($subCond) { | $pattern => $body : void | _ => () } ]>
        | _ =>
            // generate expression to replace 'when (expr is pattern) body'
            <[ match ($cond) { | true => $body : void | _ => () } ]>
        }
    | _ =>
            // generate expression to replace 'when (cond) body'
            <[ match ($cond : bool) { | true => $body : void | _ => () } ]>
    }
}

该代码使用引号来处理看起来像预定义模板的模式,并用相应的 match 表达式替换它们。例如,将宏给定的 cond 表达式与以下内容进行匹配:
<[ $subCond is $pattern when $guard ]>

检查是否符合 x is y when z 模式,并给出构成该模式的表达式。如果匹配成功,我们可以使用以下方法从获取的部分生成新的表达式:

<[
    match ($subCond)
    {
    | $pattern when $guard => $body : void
    | _ => ()
    }
]>

这会将 when (x is y when z) body 转换为基本的模式匹配表达式。这一切都是自动类型安全的,当使用不正确时会产生合理的编译错误。因此,正如你所看到的,引号提供了一种非常方便和类型安全的操作代码的方式。

4

当您希望以编程方式操作代码或进行元编程时,引用使其更具声明性,这是一件好事。

我已经写了两篇关于如何在Nemerle中轻松实现这一点的文章:这里这里

对于真实的示例,有趣的是要注意,Nemerle本身将许多常见语句定义为宏(其中使用引用)。一些例子包括:ifforforeachwhilebreakcontinueusing


2
我认为在 F# 和 Nemerle 中,引用的用途有很大的不同。在 F# 中,您不使用引用来扩展 F# 语言本身,而是使用它们来获取某个以标准 F# 编写的程序的 AST(代码的数据表示)。
在 F# 中,这可以通过将一段代码包装在 <@ ..F# code.. @> 中或者为函数添加一个特殊的属性来完成:
[<ReflectedDefinition>]
let foo () = 
  // body of a function (standard F# code)

罗伯特已经提到了这种机制的一些用途 - 你可以拿着代码将 F# 翻译成 SQL 以查询数据库,但是还有其他几个用途。例如:

据我所知,函数式编程范式(在这种情况下是一个相当粗略的术语)始终可以通过其自身进行扩展 :),这是我的理解。 - madcyree

1
正如Jordão已经提到的,引用使元编程成为可能。其中一个现实世界的例子是使用引用将F#翻译成另一种语言,例如SQL。通过这种方式,引用与C#中的表达式树具有相同的目的:它们使linq查询能够被翻译成SQL(或其他数据访问语言),并针对数据存储执行。

1

Unquote是引用使用的一个真实例子。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接