2010-01-03 6 views
22

Ich habe immer geglaubt, dass in F # wir das rec Schlüsselwort für jede rekursive Funktion zu verwenden, erforderlich, zum Beispiel:Aufzeichnungstyp rekursiven Elementfunktionen und das „rec“ Stichwort

let rec factorial = function 
| 0 -> 1 
| k when k > 0 -> k * (factorial (k - 1)) 
| failwith "oops!" 

Heute habe ich um spiele mit F # und ich kam mit einem Code ähnlich dem folgenden up:

let MyRecordType = 
    { Something  : float; 
     SomethingElse : int } 
    with 
     static member factorial = function 
      | 0 -> 1 
      | k when k > 0 -> k * (MyRecordType.factorial (k - 1)) 
      | failwith "oops!" 

wie Sie sehen, habe ich definiert nur eine rekursive Funktion, aber ich gemacht, was zunächst wie ein Fehler schien: ich habe vergessen, das zu erklären, Funktion als rekursiv mit dem Schlüsselwort rec.

Aber zu meiner Überraschung kompiliert! Und es gibt noch mehr: Wenn Sie das Schlüsselwort rec hinzufügen, dann handelt es sich um einen Syntaxfehler!

type MyRecordType = 
    { (* ... *) } 
    with 
     // syntax error: 
     static member rec factorial = function 
     (* ... *) 

Ich habe für eine Erklärung gegoogled, aber nichts bekommen. In der MSDN-Dokumentation konnte ich keine Erwähnung des Schlüsselworts rec außerhalb the page about recursive functions finden, und seit 2010-01-03 erwähnt es den Fall nicht, über den ich frage.

Genau dasselbe passiert mit nicht statischen Mitgliedern.

Also, Warum ist es ein Syntaxfehler, das Schlüsselwort rec auf Elementfunktionen eines Datensatztyps zu verwenden?

Antwort

16

Bei 'let rec' geht es nicht darum, rekursive Funktionen zu definieren, sondern um eine Bindung in einer Umgebung zu definieren, die die Bindung für die aktuelle Variable enthält, die gebunden werden soll. Sie könnten "let rec" genauso gut verwenden, um z. eine unendliche Liste. Oft möchten Sie nicht, dass die Bindung in die Umgebung eingeschlossen wird, da Sie möglicherweise auf eine frühere Variable mit demselben Namen zugreifen möchten.

Wenn Sie die statische Elementfunktion factorial definieren, suchen Sie nicht nach einer Bindung für eine Variable "faktoriell", sondern nach einem Typ 'MyRecordType' (der in der Umgebung als Typdefinition definiert ist). und wenn es zufällig eine statische Elementfunktion hat, die "faktoriell" genannt wird, die es hat.

+0

Interessant. Vielen Dank. Nur eine Frage: Wie ** oft ** wollen wir auf einen früheren Wert mit dem gleichen Namen zugreifen (mir scheint es zumindest etwas sehr selten)? Warum sollte jemand das brauchen? –

+1

Richtig, ich denke, das "oft" in meiner Antwort ist irreführend. Ich hätte "manchmal" sagen sollen. Sie können Ihre neue Variable immer in eine Datei umbenennen, die nicht mit einem früheren Variablennamen kollidiert, wenn Sie darauf zugreifen müssen. Manchmal kann die Wiederverwendung des Variablennamens einfacher sein. Ich habe kein gutes Beispiel, aber z. etwas wie 'let tot1 = a + b in sei tot2 = tot1/10 in sei tot3 = tot2 + 8 in sei tot4 = tot3% 15 in tot4' wäre normalerweise besser zu lesen (und zu modifizieren!) wenn es 'lassen' wäre tot = a + b zu tot = tot/10 zu tot = tot + 8 zu tot = tot% 15 zu tot '. – Sami

16

Alle "member" -Funktionen sind implizit "rec" innerhalb des Typs, in dem sie definiert sind.

+1

Danke. Es wäre schön, dies irgendwo auf MSDN für das RTM dokumentiert zu haben! –

+0

Genau das, was ich gesucht habe –