Reputation: 9026
Why do Bind1 and Bind2 have different signatures?
type T() =
let bind(v, f) = v
member self.Bind1 = bind
member self.Bind2(a, b) = bind(a, b)
fsi reports them as
type T =
class
new : unit -> T
member Bind2 : a:'a * b:'b -> 'a
member Bind1 : (obj * obj -> obj)
end
This came up when I was playing with some computation expressions and couldn't figure out why I was getting an error message about Bind not being defined. Bind1-style didn't work, Bind2 did, and I couldn't figure out why.
Given the same objects, they do return the same result:
> q.Bind1(1:>obj,3:>obj);;
val it : obj = 1
> q.Bind2(1:>obj,3:>obj);;
val it : obj = 1
>
Using Microsoft F# Interactive, (c) Microsoft Corporation, All Rights Reserved F# Version 1.9.7.4, compiling for .NET Framework Version v4.0.21006
Upvotes: 3
Views: 291
Reputation: 13862
Bind1 is a get property that returns a function while bind2 is a function. You can see the get accessor if you evaluate bind1 and bind2 from an instance.
> let t = new T();;
val t : T
> t.Bind1;;
val it : (obj * obj -> obj) = <fun:get_Bind1@3>
> t.Bind2;;
val it : ('a * 'b -> 'a) = <fun:it@10>
You wrote the shorthand of
member self.Bind1
with get() = bind
Using reflector you can see in Bind1 where obj comes from and the function object.
internal class get_Bind1@7 : FSharpFunc<Tuple<object, object>, object>
{
// Fields
public T self;
// Methods
internal get_Bind1@7(T self)
{
this.self = self;
}
public override object Invoke(Tuple<object, object> tupledArg)
{
object v = tupledArg.get_Item1();
object f = tupledArg.get_Item2();
return this.self.bind<object, object>(v, f);
}
}
Along with what kvb said you can add type annotation to the class to avoid the generic objects.
type T<'a, 'b>() =
let bind(v:'a, f:'b) = (v:'a)
member self.Bind1 = bind
member self.Bind2(a, b) = bind(a, b)
type T<'a,'b> =
class
new : unit -> T<'a,'b>
member Bind2 : a:'a * b:'b -> 'a
member Bind1 : ('a * 'b -> 'a)
end
Upvotes: 7
Reputation: 55184
To elaborate on Erik's answer, because it is impossible to have generic properties on .NET objects, F# has to pick non-generic types for v
and f
, which default to obj
. You could choose other specific types and use a type annotation to give Bind1
a different (but still non-generic) signature.
Upvotes: 4