为什么这两种方法的签名不同?

时间:2009-12-21 20:26:45

标签: f#

为什么Bind1和Bind2有不同的签名?

type T() =
  let bind(v, f) = v
  member self.Bind1 = bind
  member self.Bind2(a, b) = bind(a, b)

fsi将其报告为

type T =
  class
    new : unit -> T
    member Bind2 : a:'a * b:'b -> 'a
    member Bind1 : (obj * obj -> obj)
  end

当我正在使用一些计算表达式时出现这种情况,并且无法弄清楚为什么我收到有关Bind未定义的错误消息。 Bind1风格不起作用,Bind2做了,我无法弄清楚原因。

给定相同的对象,它们会返回相同的结果:

> q.Bind1(1:>obj,3:>obj);;
val it : obj = 1
> q.Bind2(1:>obj,3:>obj);;
val it : obj = 1
> 

使用Microsoft F#Interactive,(c)Microsoft Corporation,保留所有权利 F#版本1.9.7.4,编译.NET Framework版本v4.0.21006

2 个答案:

答案 0 :(得分:7)

Bind1是一个get属性,返回一个函数,而bind2是一个函数。如果从实例中评估bind1和bind2,则可以看到get访问器。

> 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>

你写了

的简写
member self.Bind1
   with get() = bind

使用reflector,您可以在Bind1中看到obj来自哪里以及函数对象。

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);
    }
}

除了kvb所说的你可以在类中添加类型注释以避免泛型对象。

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

答案 1 :(得分:4)

详细说明Erik的答案,因为在.NET对象上不可能有通用属性,F#必须选择vf的非泛型类型,默认为{{1} }。您可以选择其他特定类型并使用类型注释为obj提供不同的(但仍然是非通用的)签名。