将变量定义注入 F# 引用

Injecting a variable definition into F# quotation

我有一个自定义变量定义,我想将其插入到引文中。甚至可以使用引号语法糖吗?

我想做的事情:

open Microsoft.FSharp.Quotations
let var = Var("myvar", typeof<int>)
let op = <@@ fun l -> match l with
        | [] -> 0
        | %%myvar :: _ -> ... @@>

我也试过 <@@ let %%myvar = ... @@> 有类似的目的。

在这两种情况下,我都得到了 FS0010 "Unexpected prefix operator in binding",或“...在模式匹配中”。

有没有办法像这样注入现有的 Var?还是我必须求助于手动生成整个表达式?

PS:我正在使用整个东西将其他一些 AST 翻译成 F# 引用。

你在问题中描述的内容确实有点荒谬。你不能拼接一个Var into an expression. Only a value of type Expr can be spliced. If you created an instance of Expr our of your var via the Expr.Var constructor,那么拼接是可以的:

let var = Expr.Var( Var("myvar", typeof<int>) )
let op = <@@ fun l -> %%var @@>

但这不会让你做你想做的事:你不能在模式位置拼接表达式([=21= 中箭头 -> 的左侧] 就是我们所说的 "pattern",let 中等号 = 的左侧也是如此。您只能拼接表达式,不能拼接语法的其他部分。 F# 代码引用并不像 Lisp 宏或 TemplateHaskell 那样免费。

诚然,您实​​际上想要做什么并不完全清楚。


想到您的真实意图的一种可能性是:您想要匹配箭头左侧的这个变量 ->,然后将它传递给将构造右侧的其他函数箭头 ->。像这样:

let mkRightSide var = <@@ %%var + 42 @@>

let var = Expr.Var( Var("myvar", typeof<int>) )
let op = <@@ fun l -> match l with
             | [] -> 0
             | %%var :: _ -> %%(mkRightSide var)   // Doesn't compile
         @@>

这将产生以下报价:

fun l -> match l with
| [] -> 0
| myvar :: _ -> myvar + 42

如果这是你的意图,那么我建议使用 mkRightSide return 一个函数,它只需将 myvar 作为参数:

let mkRightSide = <@@ fun myvar -> myvar + 42 @@>

let op = <@@ fun l -> match l with
             | [] -> 0
             | (myvar:int) :: _ -> (%%mkRightSide) myvar @@>

以上将产生以下报价:

fun l -> match l with
| [] -> 0
| myvar :: _ -> (fun myvar -> myvar + 42) myvar

注意 1: myvar 上的类型注释是必要的,因为您的引文是未键入的。由于 mkRigthSide 不携带类型信息,编译器无法将 myvar 推断为 int 而是将其设为泛型,这会在尝试拼接时导致类型不匹配。

注2: (%%mkRightSide)两边的括号是必须的。没有它们,编译器会将其理解为 %%(mkRightSide myvar),因为函数应用程序的优先级高于 %% 运算符。


如果我猜错了你的意图,请澄清,我很乐意修改答案。