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.

+3


source to share


1 answer


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)

+3


source







All Articles