3

我遇到了“引用”一词,我试图找出一些使用它的真实例子。每个代码表达式都有 AST 的能力听起来很棒,但是如何在现实生活中使用它呢?

有谁知道这样的例子?

4

5 回答 5

5

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

内梅尔

在 Nemerle 中,在宏中使用引号来分解代码片段并生成新代码。许多语言本身都是以这种方式实现的。例如,这里有一个来自官方库的示例——实现when条件构造的宏。Nemerle 没有语句,因此 anif必须有一个elsepart:when并且unless宏分别为 anif提供了一个空的thenelsepart 的简写。该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为基本的模式匹配表达式。所有这些都是自动类型安全的,并且在使用不正确时会产生合理的编译错误。因此,正如您所见,引用提供了一种非常方便且类型安全的代码操作方式。

于 2011-09-24T21:05:07.203 回答
4

好吧,任何时候你想以编程方式操作代码,或者做一些元编程,引用使它更具声明性,这是一件好事

我写了两篇关于这如何让 Nemerle 的生活更轻松的文章:herehere

对于现实生活中的示例,有趣的是,Nemerle 本身将许多常见语句定义为宏(使用引号)。一些示例包括:ifforforeachwhilebreak和。continueusing

于 2011-09-23T13:17:21.057 回答
2

我认为引文在 F# 和 Nemerle 中有完全不同的用途。在 F# 中,您不使用引号来扩展 F# 语言本身,而是使用它们来获取用标准 F# 编写的某些程序的 AST(代码的数据表示)。

在 F# 中,这可以通过将一段代码包装在 中来完成<@ ..F# code.. @>,或者通过向函数添加特殊属性来完成:

[<ReflectedDefinition>]
let foo () = 
  // body of a function (standard F# code)

Robert 已经提到了这种机制的一些用途——您可以将代码转换为 F# 到SQL 以查询数据库,但还有其他几种用途。例如,您可以:

于 2011-09-23T14:14:33.227 回答
1

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

于 2011-09-23T14:01:08.437 回答
1

Unquote是引用用法的真实示例。

于 2011-09-23T19:47:51.700 回答