如何使用F#在记录结构上定义fmap [英] How to define a fmap on a record structure with F#

查看:118
本文介绍了如何使用F#在记录结构上定义fmap的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有可能为记录创建一个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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆