1

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

标题下的第二个代码片段,Composition Function具有以下代码片段。

#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# 交互式 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

4

2 回答 2

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 行左右是 >>> 的定义和其他炫耀内联和其他漂亮东西的定义。

于 2009-04-22T02:28:20.967 回答
3

借助更多信息,F# 可以确定使用浮点参数调用 xSquared。如果您将 negXPlusFive 更改为“let negXPlusFive x = -x + 5”,您会发现它,fog 和 xSquared 将是“int -> int”。

于 2009-04-22T00:36:41.517 回答