FSharp 在基础中调用泛型方法 class
FSharp calling a generic method in a base class
此问题基于本课程第一周的函数式随机生成器: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 方法 class 以便可以使用这样的代码创建新类型的生成器
let integers = new IntGenerator()
let booleans = integers.Map (fun x -> x > 0)
所以,这是我修改基础的方法 class
[<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
相同
我不明白为什么。我确定我被一些简单的事情绊倒了。
这里的问题是您必须小心 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
}
注意 this
和 base
以及 __
的区别 ;)
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-map; )
免责声明 但当然,由于生成器很不纯 none 函子定律将真正成立(如果您不修复系统时间)
此问题基于本课程第一周的函数式随机生成器: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 方法 class 以便可以使用这样的代码创建新类型的生成器
let integers = new IntGenerator()
let booleans = integers.Map (fun x -> x > 0)
所以,这是我修改基础的方法 class
[<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
相同我不明白为什么。我确定我被一些简单的事情绊倒了。
这里的问题是您必须小心 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
}
注意 this
和 base
以及 __
的区别 ;)
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-map; )
免责声明 但当然,由于生成器很不纯 none 函子定律将真正成立(如果您不修复系统时间)