2009-04-22 2 views
1

Ich folgte einige Beispiele auf F# Wikibook on High Order Functions.Warum gibt die F # -Funktion eine Signatur von "val FunctionName: int -> int" zurück?

Zweites Code-Snippet unter Titel, Komposition Funktion hat folgenden Code-Ausschnitt.

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

Die, den ich Problem Verständnis habe ist

let xSquared x = x*x 

Wenn ich es mit F # interaktiv Shell laufe (fsi.exe) von selbst, ich die folgenden Signatur erhalten.

> let xSquared x = x*x;; 

val xSquared : int -> int 

Aber wenn ich den ganzen Code-Schnipsel laufen, xSquared gibt die folgenden.

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

Warum xSquared nimmt float und gibt float?

Antwort

3

Mit weiteren Informationen kann F # ermitteln, dass xSquared mit Float-Argumenten aufgerufen wird. Wenn Sie negXPlusFive in etwas wie "let negXPlusFive x = -x + 5" ändern, würden Sie feststellen, dass es sich bei "fog" und "xSquared" um "int -> int" handelt.

+0

Es sieht so aus, als ob F # Argumenttypen ableitet, abhängig davon, wie viel F # über den Kontext weiß, in dem die Methode erstellt wurde. Vielen Dank. – Sung

+0

F # tut dies nur, wenn es den Polymorphismus des Werts einschränken muss. In diesem Fall kann x nicht "a" sein. es muss es auf einen einzigen Typ beschränken. – MichaelGG

11

auf zu erweitern, was Sebastian sagte und was tagged jleedev, eine Funktion wie:

let xSquared x = x*x 

Kann nur auf eine Art arbeiten, * ein Operator hat. Standardmäßig gewinnt int in diesen Situationen. Es kann nicht wirklich generisch sein, da .NET keine Möglichkeit bietet, die Einschränkung "jeden Typ, der * hat" darzustellen.

F # unterstützt jedoch Inlining, wodurch Funktionen generischer werden können, da sie in jede Callsite eingebunden sind. Dies ermöglicht Ihnen, eine Funktion wie xSquared zu haben, die auf Gleitkommazahlen, Ints, usw. funktioniert, - jeden Typ mit einem * Operator.

> let inline xSquared x = x*x;; 

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

Jetzt beachten Sie, wie der Funktionstyp ist^a ->^b. Dies ist ähnlich wie 'a ->' b, außer dass die Typvariablen statisch aufgelöst werden müssen. Da F # keine Typklassen hat, werden Operatoren so behandelt.

Sie können tatsächlich Ihre eigene Art mit eigenem * Mitglied definieren zu tun, was Sie wünschen, und es würde mit xSquared arbeiten:

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" 

Öffnen Sie einfach Prim-types.fs in Ihrem F # Distro und stecken um. Um Linie 2200 sind die Definitionen für >>> und andere, die Inlining und andere nette Dinge zeigen.

+0

Danke, MichaelGG für genauere Erklärungen – Sung

+0

Cool, ich habe hier was gelernt! – Benjol