首页 文章

FSharp在基类中调用泛型方法

提问于
浏览
3

此问题基于本课程第一周的功能随机生成器: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的调用似乎将类型“b”限制为“a”

我不明白为什么 . 我确定我正在匆匆忙忙做一些简单的事情 .

1 回答

  • 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 
            }
    

    但我不建议你这样做,因为你得到一个伪装的看起来很有 Value 的方法: 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-map;)

    disclaimer 但当然因为发电机很遗憾不存在任何算子法律都没有(如果你不修复你的系统时间)

相关问题