将变量定义注入F#引用

时间:2018-05-13 16:52:14

标签: f# quotations

我有一个自定义变量定义,我想插入引号。它甚至可以用引号语法糖吗?

我想做什么:

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

我也试过<@@ let %%myvar = ... @@>,但目的与此类似。

在这两种情况下,我都有FS0010“绑定中的意外前缀运算符”,或“......模式匹配”。

有没有办法注入像这样的现有Var?或者我是否必须手动生成整个表达式?

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

1 个答案:

答案 0 :(得分:1)

您在问题中描述的内容实际上是荒谬的。您无法将Var拼接成表达式。只能拼接Expr类型的值。如果您通过Expr.Var constructor创建了Expr var我们let var = Expr.Var( Var("myvar", typeof<int>) ) let op = <@@ fun l -> %%var @@> 的实例,则可以拼接:

->

但是这不会让你做你想做的事情:你不能在模式位置拼接表达式(match内的箭头=的左侧是我们称之为“模式”,let内的等号->的左侧也是如此。您只能拼接表达式,而不能拼接语法的其他部分。 F#代码引用并不像Lisp宏或TemplateHaskell那样完全免费。

不可否认,你真正想要做的事情并不完全清楚。

您想到的真实意图的一种可能性是:您希望在箭头->的左侧匹配此变量,然后将其传递给构建右侧的其他函数。 arrow 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

如果这是您的意图,那么我建议让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

以上将产生以下报价:

myvar

注1: mkRigthSide上的类型注释是必要的,因为您的报价是无类型的。由于myvar不包含任何类型信息,因此编译器无法将int推断为(%%mkRightSide)并使其成为通用的,这会在尝试拼接时导致类型不匹配。

注意2: %%(mkRightSide myvar)周围的括号是必要的。如果没有它们,编译器会将其理解为%%,因为函数应用程序的优先级高于type Task err ok = Task 运算符。

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