将变量定义注入 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)
,因为函数应用程序的优先级高于 %%
运算符。
如果我猜错了你的意图,请澄清,我很乐意修改答案。
我有一个自定义变量定义,我想将其插入到引文中。甚至可以使用引号语法糖吗?
我想做的事情:
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)
,因为函数应用程序的优先级高于 %%
运算符。
如果我猜错了你的意图,请澄清,我很乐意修改答案。