views:

167

answers:

1

This is my code:

type Cell<'t>(initial : 't) =
    let mutable v = initial
    let callbacks = new List<'t -> unit>()
    member x.register c = callbacks.Add(c)
    member x.get () = v
    member x.set v' = 
        if v' <> v 
        then v <- v'
             for callback in callbacks do callback v'
    member x.map f = 
        let c = new Cell<_>(f v)
        x.register(fun v' -> c.set (f v')) ; c

My problem is with the map member. F# infers the type

map : ('t -> 't) -> Cell<'t>

I think it should infer this more general type (just like Seq's map):

map : ('t -> 'a) -> Cell<'a>

And in fact if I declare the type like that, Visual Studio tells me that the type 'a has been constrained to 't because of the expression (f v') in c.set (f v'). Is the problem that the new Cell is forced to have type Cell<'t> because we're in the class definition?

I'm pretty sure that's the problem because if I define map as a separate function then F# does infer the type I want:

let map f (c : Cell<_>) = 
    let c' = new Cell<_>(f (c.get ()))
    c.register(fun v' -> c'.set (f v')) ; c'

Namely

map : ('a -> 'b) -> Cell<'a> -> Cell<'b>

I would like to use a member, but this less general type makes my Cell type useless... How do I solve this problem?

Thanks! Jules

+2  A: 

I don't have a box with Beta1 handy right now (in our internal bits this now seems to infer the correct type, so hopefully that means this will be fixed in Beta2).

I expect you can specify a full type signature:

    member x.map<'a> (f:'t -> 'a) : Cell<'a> =

and it will work.

UPDATE

I tried on Beta1, and in fact the 'fix' is

member x.set (v':'t) : unit =

I am unclear why adding this type signature helps.

Brian
Thanks! That signature is strange: if you remove `: unit` or if you remove `v' : 't` then F# infers the restricted type again! And if you don't specify the signature F# infers the same type... Thanks again!
Jules