FSharp calling a generic method in a base class
This question is based on functional random generators in the first week of this course: https://www.coursera.org/course/reactive
The course is based on Scala, I am trying to replicate it in FSharp.
Here's my problem:
I have an abstract generator
[<AbstractClass>]
type Generator<'a>() =
abstract member Generate: 'a
And I have an implementation that generates random integers
type IntGenerator() =
inherit Generator<Int32>()
let rand = new System.Random()
override this.Generate = rand.Next(Int32.MinValue, Int32.MaxValue)
Now I want to add a Map method to my base class so that new generator types can be created using code like this
let integers = new IntGenerator()
let booleans = integers.Map (fun x -> x > 0)
So this is how I changed the base 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 }
Unfortunately this call to base.Generate seems to restrict the type 'b to be the same as' a
I do not understand why. I'm sure I'm stumbling over something simple.
source to share
The problem is that you have to be careful with method instance names member
:
I think this should work:
[<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
}
or if you insist on a member method:
[<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
}
note the differences with this
and base
and __
;)
BTW , this will work even without unit ->
(as you wrote it):
[<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
}
but I would not recommend this as you have overridden the cost estimation method: Generate
more idiomatic way
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)
fun fact
As you can see here (if you look closely) you will see that this map
one is actually just a Functor-map for unit -> *
;)
disclaimer , but of course, since the generators are sadly unclean, none of the executive laws will actually hold (unless you fix your system time)
source to share