为什么F#函数返回“val FunctionName:int - > int”的签名?

时间:2009-04-22 00:33:46

标签: f# monomorphism

我在F# Wikibook on High Order Functions上关注了一些例子。

标题下的第二个代码段撰写函数包含以下代码段。

#light
open System

let compose f g x = f (g x)

let xSquared x = x*x
let negXPlusFive x = -x/2.0 + 5.0

let fog = compose xSquared negXPlusFive

// ... Console.WriteLine statements....

我遇到问题的是

let xSquared x = x*x

当我用F#interactive shell(fsi.exe)单独运行它时,我得到以下签名。

> let xSquared x = x*x;;

val xSquared : int -> int

但是当我运行整个代码段时,xSquared会返回以下内容。

val compose : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b
val xSquared : float -> float
val negXPlusFive : float -> float
val fog : (float -> float)

为什么xSquared需要float并返回float

2 个答案:

答案 0 :(得分:11)

扩展Sebastian所说的以及jleedev标记的内容,如下所示:

let xSquared x = x*x

只能在具有运算符*的类型上运行。默认情况下,int在这些情况下获胜。它不能真正通用,因为.NET没有办法表示约束“任何具有*的类型。”

但是,F#支持内联,它允许函数更通用,因为它们被内联到每个调用点。这允许你有一个像浮点数,整数等一样的xSquared函数, - 任何带*运算符的类型。

> let inline xSquared x = x*x;;

val inline xSquared :
   ^a ->  ^b when  ^a : (static member ( * ) :  ^a *  ^a ->  ^b)

现在注意函数类型是如何^ a - > ^ B。这类似于'a - > 'b,除了类型变量必须静态解析。因为F#没有类型类,所以这就是操作符的处理方式。

你可以用它自己的*成员来定义你自己的类型来做任何你想做的事情,并且它适用于xSquared:

type Foo(x) =
    member this.Y = x - 1
    static member (*) (x:Foo, y:Foo) = string <| x.Y * y.Y + 1

let a = Foo(10);;

type Foo =
  class
    new : x:int -> Foo
    member Y : int
    static member ( * ) : x:Foo * y:Foo -> string
  end
val a : Foo

> xSquared a;;
val it : string = "82"

在你的F#发行版中打开prim-types.fs然后四处寻找。第2200行附近是&gt;&gt;&gt;的定义。和其他炫耀内联和其他漂亮的东西。

答案 1 :(得分:3)

有了更多信息,F#可以确定使用float参数调用xSquared。如果你将negXPlusFive更改为“let negXPlusFive x = -x + 5”,你会发现它,fog和xSquared将是“int - &gt; int”。