FSharp在基类中调用泛型方法

时间:2015-04-17 10:51:32

标签: f#

此问题基于本课程第一周的功能随机生成器:https://www.coursera.org/course/reactive

该课程以Scala为基础,我试图在FSharp中复制它。

这是我的问题:

我有一个抽象的生成器

[<AbstractClass>]
type Generator<'a>() = 
    abstract member Generate: 'a

我有一个生成随机整数的实现

type IntGenerator() =
    inherit Generator<Int32>()

    let rand = new System.Random()
    override this.Generate = rand.Next(Int32.MinValue, Int32.MaxValue)

现在,我想在我的基类中添加一个Map方法,以便可以使用这样的代码创建新类型的生成器

let integers = new IntGenerator()        
let booleans = integers.Map (fun x -> x > 0)

所以,这是我修改基类

的方法
[<AbstractClass>]
type Generator<'a>() = 
    abstract member Generate: 'a
    member this.Map (f:'a -> 'b) = { new Generator<'b>() with member this.Generate = f base.Generate }

不幸的是,对base.Generate的调用似乎将类型&#39; b限制为&#39; a

我不明白为什么。我确定我会踩到简单的东西。

1 个答案:

答案 0 :(得分:3)

这里的问题是你必须小心member方法的实例名称:

我认为这应该成功:

[<AbstractClass>]
type Generator<'a>() = 
    abstract member Generate: unit -> 'a
    static member Map (f:'a -> 'b) = 
        fun (g : Generator<'a>) ->
        { new Generator<'b>() with 
            member this.Generate () = g.Generate () |> f 
        }

或者你坚持使用会员方法:

[<AbstractClass>]
type Generator<'a>() = 
    abstract member Generate: unit -> 'a
    member this.Map (f:'a -> 'b) : Generator<'b> = 
        { new Generator<'b>() with 
            member __.Generate () = this.Generate () |> f 
        }

注意与thisbase以及__的差异;)

BTW 这甚至可以在没有unit ->的情况下工作(正如您所写的那样):

[<AbstractClass>]
type Generator<'a>() = 
    abstract member Generate: 'a
    member this.Map (f:'a -> 'b) : Generator<'b> = 
        { new Generator<'b>() with 
            member __.Generate = this.Generate |> f 
        }

我不推荐这样做,因为你在伪装中得到一个看起来很有价值的方法:Generate

更惯用的方式

type Generator<'a> = unit -> 'a

module Generator =
    let map (f:'a -> 'b) (g : Generator<'a>) =
        fun () -> g () |> f

    let intGenerator : Generator<int> =
        let rand = new System.Random()
        fun () -> rand.Next(System.Int32.MinValue, System.Int32.MaxValue)

有趣的事实

正如您在此处看到的那样(如果您仔细观察),您会发现此map实际上只是unit -> * Functor - 地图;)

免责声明但当然,由于生成器很遗憾,所以没有任何一个算法将会真正存在(如果你不修复你的系统时间)