如何使用F#在记录结构上定义fmap [英] How to define a fmap on a record structure with F#
问题描述
是否有可能为记录创建一个fmap,以便我可以应用相同的函数来记录类似bur不同类型的字段
is there a possibility to create an fmap for records so that I can apply the same function to record fields of similar bur different types
假设我有一个记录字段类型项目
和记录 X
和函数转换
Let say I have a record field type Item
and a record X
and function transform
type Item<'a, 'b> = Item of 'a * 'b
let transform (i: Item<'a, 'b>) : Item<'a, string> =
let (Item (x, y)) = i
Item (x, sprintf "%A" y)
type X<'a> = {
y: Item<'a, int>
z: Item<'a, bool>
}
with
member inline this.fmap(f) =
{
y = f this.y
z = f this.z
}
现在行 z = f this.z
抱怨给定的类型应为 Item<'a,int>
但其类型为 Item<'a,bool>
。显然,因为类型提交者
已经确定函数 f
的类型为 Item<'a,int> - >商品< ...>
但是我希望 f
应用多态。我怎么能完成这个?
now the line z = f this.z
complains that the given type should be of Item<'a, int>
but its of type Item<'a, bool>
. Obviously as the type infererrer
has decided that the function f
is of type Item<'a, int> -> Item<...>
however i want f
to be applied polymorphic. How can I get this done?
欢迎邪恶的黑客攻击!
推荐答案
一个显而易见的解决方案是使用 bimap
而不是 fmap
,然后在调用者站点使用两倍的函数:
An obvious solution is to use bimap
instead of fmap
and then wirte twice the function at the caller site:
type Item<'a, 'b> = Item of 'a * 'b
let transform (i: Item<'a, 'b>) : Item<'a, string> =
let (Item (x, y)) = i
Item (x, sprintf "%A" y)
type X<'a> = {
y: Item<'a, int>
z: Item<'a, bool>
}
with
member inline this.bimap(f, g) =
{
y = f this.y
z = g this.z
}
另一种选择(这里是邪恶类型的黑客)而不是传递一个函数,传递我称之为'Invokable'的东西,其中某种函数用一个名为 Invoke
的方法包装在一个类型中。像委托但是静态的东西。
Another alternative (here's the evil type hack) is instead of passing a function, pass what I call an 'Invokable' which some kind of function wrapped in a type with a single method called Invoke
. Something like a delegate but static.
这是一个例子。为简单起见,我使用 $
而不是调用
:
Here's an example. I use $
instead of Invoke
for simplicity:
let inline fmap invokable ({y = y1; z = z1}) = {y = invokable $ y1; z = invokable $ z1}
type Id = Id with
static member ($) (Id, Item (a,b)) = Item (id a, id b)
type Default = Default with
static member ($) (Default, Item (a:'t,b:'u)) =
Item (Unchecked.defaultof<'t>, Unchecked.defaultof<'u>)
let a = {y = Item ('1', 2); z = Item ('3', true) }
let b = fmap Id a
let c = fmap Default a
现在问题是我想不出很多其他有用的功能。可以吗?
Now the problem is I can't think of many other useful functions. Can you?
否则,如果你使它更通用:
Otherwise if you make it more generic:
type X<'a, 'b, 'c> = {
y: Item<'a, 'b>
z: Item<'a, 'c>
}
然后你可以使用像这样的Invokable:
then you can for instance use an Invokable like this:
type ToList = ToList with static member ($) (ToList, Item (a,b)) = Item ([a], [b])
let d = fmap ToList a
// val d : X<char list,int list,bool list> = {y = Item (['1'],[2]);
z = Item (['3'],[true]);}
参见此相关问题。提出的案例比较简单,但问题是相同的。
See also this related question. The case presented there is simpler but the problem is the same.
此外这个是相关的。
这篇关于如何使用F#在记录结构上定义fmap的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!