我有一个自定义变量定义,我想插入引号。它甚至可以用引号语法糖吗?
我想做什么:
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#报价。
答案 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
运算符。
如果我猜错了你的意图,请澄清一下,我很乐意修改答案。