F# 引用可以用于创建适用于任意 F# 记录类型的函数吗?
给定一个 F# 记录:
type R = { X : string ; Y : string }
和两个对象:
let a = { X = null ; Y = "##" }
let b = { X = "##" ; Y = null }
以及字符串上的谓词:
let (!?) : string -> bool = String.IsNullOrWhiteSpace
和一个函数:
let (-?>) : string -> string -> string = fun x y -> if !? x then y else x
有没有办法使用 F# 引号来定义:
let (><) : R -> R -> R
和行为:
let c = a >< b // = { X = a.X -?> b.X ; Y = a.Y -?> b.Y }
以某种方式让 (><) 适用于任何任意 F# 记录类型,不仅仅适用于
R
。
短:给定任意记录类型和补码函数 ( -?>)
适用于其字段吗?
如果不能使用引用,那什么可以呢?
Given an F# record:
type R = { X : string ; Y : string }
and two objects:
let a = { X = null ; Y = "##" }
let b = { X = "##" ; Y = null }
and a predicate on strings:
let (!?) : string -> bool = String.IsNullOrWhiteSpace
and a function:
let (-?>) : string -> string -> string = fun x y -> if !? x then y else x
is there a way to use F# quotations to define:
let (><) : R -> R -> R
with behaviour:
let c = a >< b // = { X = a.X -?> b.X ; Y = a.Y -?> b.Y }
in a way that somehow lets (><)
work for any arbitrary F# record type, not just for R
.
Short: Can quotations be used to generate F# code for a definition of (><)
on the fly given an arbitrary record type and a complement function (-?>)
applicable to its fields?
If quotations cannot be used, what can?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以使用 F# 引用为每个特定记录构造一个函数,然后使用 F# PowerPack 中提供的引用编译器对其进行编译。然而,正如评论中提到的,使用 F# 反射肯定更容易:
该函数获取记录,动态获取其字段,然后将
f
应用于字段。您可以使用它来实现您的运算符,如下所示(我使用的是具有可读名称的函数):使用反射的解决方案非常容易编写,但效率可能较低。每次调用函数
applyOnFields
时,都需要运行 .NET Reflection。如果您知道记录类型,您可以使用引号来构建表示您可以手写的函数的 AST。例如:使用引用生成函数更加困难,因此我不会发布完整的示例,但以下示例至少显示了其中的一部分:
一旦构建了正确的引用,就可以使用 F# PowerPack 对其进行编译。请参阅此代码段示例。
You could use F# quotations to construct a function for every specific record and then compile it using the quotation compiler available in F# PowerPack. However, as mentioned in the comments, it is definitely easier to use F# reflection:
This function takes records, gets their fields dynamically and then applies
f
to the fields. You can use it to imiplement your operator like this (I'm using a function with a readable name instead):The solution using Reflection is quite easy to write, but it might be less efficient. It requires running .NET Reflection each time the function
applyOnFields
is called. You could use quotations to build an AST that represents the function that you could write by hand if you knew the record type. Something like:Generating the function using quotations is more difficult, so I won't post a complete sample, but the following example shows at least a part of it:
Once you build the right quotation, you can compile it using F# PowerPack. See for example this snippet.