F#, Funktionale Programmierung mit .NET, Teil 2

10. Februar 2008 – 19:23 von Andreas

In diesem Teil werden folgende Themen behandelt: Definieren von Funktionen, Rekursion, Definieren eigener Operatoren

Definieren von Funktionen

Das Definieren einer einfachen Funktion gestaltet sich sehr einfach:

  1. (* Das ist ein mehrzeiliger Kommentar:
  2.     Funktion multipliziert 2 Zahlen *)
  3. let multi a b = a * b
  4. // Die Funktion 3*4 berechnen lassen und das Ergebnis in result speichern
  5. let result = multi 3 4
  6. // Ausgabe des Ergebnis
  7. printfn "3*4=%i" result

Wie auch beim Definieren von Variablen ist das Schlüsselwort “let” der Funktion vorangestellt. Darauf folgt der Bezeichner “muti”. a und b sind die Parameter der Funktion. Ich muss also keinen Rückgabetyp angeben! Genauso ist es mir selbst überlassen den Rückgabetyp zu verwenden oder nicht.

Definieren wir nun eine zweite etwas anspruchsvollere Funktion, welche unsere erste u.a. verwendet:

  1. // Multipliziert Parameter mit 4 und addiert 2 hinzu
  2. let multi4andAdd2 n =
  3.     // Die Funktion multi wird nur mit einem Parameter aufgerufen,
  4.     //obwohl diese eigentlich 2 Parameter erwartet! *)
  5.     let multiFour = multi 4
  6.     // Hier wird nun der 2. fehlende Parameter uebergeben (in
  7.     // unserem Fall n).
  8.     // Das macht hier wenig Sinn und dient rein der Verdeutlichung,
  9.     // wie eine partial/curried function verwendet werden kann.
  10.     let res = multiFour n
  11.     // Eine 2. Funktion, welche innerhalb der Funktion multi4andAdd2
  12.     // definiert ist
  13.     let Add2 value =
  14.         value + 2
  15.     // Innere Funktion aufrufen
  16.     Add2 res
  17.  
  18. // Testen unserer neuen Funktion:
  19. let endresult = multi4andAdd2 5
  20. printfn "5 multi4andAdd2=%i" endresult

In diesem Beispiel findet man gleich mehrere F#-Features. Eines davon sind die partial/curried functions. Dabei muss man einer Funktion nicht sofort die komplette Anzahl an geforderten Parametern mitgeben. Bei “let multiFour = multi 4″ fehlt nun z.B. der 2. Parameter! F# sieht dies und merkt sich diesen unvollständigen Zustand! Es überträgt den fehlenden Parameter auf die Funktion multiFour weiter. D.h. wenn ich mutliFour aufrufen will muss ich nun hier den fehlenden Parameter angeben, so dass der Code korrekt ausgeführt werden kann: “let res = multiFour n”. D.h. also ich kann fehlende Parameter einfach an andere “Aufruffunktionen” weitergeben. Dies scheint auf den ersten Blick nicht sehr wichtig oder sinnvoll zu sein, ist aber ein mächtiges Feature der funktionalen Programmierung.

Ein 2. Sprachfeature sind die inneren Funktionen, welche ein gutes Mittel sind, um lange Codeabschnitte einer Funktion in kleinere Portionen zu packen, und somit übersichtlicheren und leichter wartbaren Code zu schaffen. Die Funktion “Add2″ ist z.B. innerhalb der Funktion “multi4andAdd2″ definiert. Durch die Einrückung gilt “Add2″ im Scope der Funktion “multi4andAdd2″!

Rekursion:

Betrachten wir nun folgendes Rekursionsbeispiel:

  1. // Funktion imvertiert den uebergebenen string
  2. let rec invertText (textToInvert : string) =
  3.     // Rekursionsbremse
  4.     if (textToInvert.Length = 0) then
  5.         textToInvert
  6.     else
  7.         // Invertiere
  8.         invertText(textToInvert.Substring(1))  + textToInvert.Substring(0,1)
  9.  
  10. let text = "Andi"
  11. let invertedText = invertText text
  12. printfn "Der invertierte Text von Andi ist: %s" invertedText

Diese Funktion invertiert den übergebenen Text rekursiv. Sofort fällt das Schlüsselwort “rec” auf, welches bei der Definition der Funktion nach dem “let” steht! Jede Funktion, die rekursiv aufrufbar sein soll muss dieses Schlüsselwort haben. Ansonsten ist die Rekursion nicht erlaubt! Auch schön zu sehen ist, wie man einen Datentyp explizit angeben kann: “(textToInvert : string)” besagt in unserem Beispiel, dass die Variable textToInvert vom Typ string sein muss. Der Name des Typs der Variablen folgt also nach dem Doppelpunkt “:”.

Definieren eigener Operatoren

Als letztes gehe ich noch kurz darauf ein, wie man eigene Operatoren definieren kann:

  1. // Definiere eigenen Operator *:- welcher
  2. // zuerst a und b multipliziert und dann a
  3. // vom Ergebnis subtrahiert
  4. let ( *:- ) a b = a*b-a
  5. printfn "(3*2-3: 3 *:- 2) = %i" (3 *:- 2)

Benutzerdefinierte Operatoren können mit folgenden Zeichen beginnen: !$%&*+-./<=>?@^|~
und diese Zeichen, inklusive des Doppeltpunktes “:” verwenden. Der Operator wird außerdem innerhalb von Klammern definiert.

Aaron hatte die coole Idee nach jedem Post zu F# eine kleine Aufgabe zu stellen, um das Tutorial ein bisschen interaktiv zu gestalten! Da ich dies für einen super Vorschlag halte werde ich das hiermit auch machen!

Die erste Aufgabe lautet also: Definiere einen eigenen Operator “!” welcher die Fakultät einer Zahl berechnen soll!
Folgende Zeile sollte den Output “Die fakultaet von 5 ist 120″ liefern:

  1. let endresult = !5
  2. printfn "Die fakultaet von 5 ist %i" endresult

Die Lösungen könnt Ihr gerne als Kommentar zu diesem Bolgeintrag posten!
Ich selbst werde in ca. einer Woche die Lösung als Blogeintrag posten! Ich freue mich auf eure Lösungen! Viel Spaß:)

  1. 3 Responses to “F#, Funktionale Programmierung mit .NET, Teil 2”

  2. Ich habe hier mal meinen Lösungsvorschlag für die Aufgabe. Außerdem gibt’s ein kleines F# unter Linux HowTo mit oben drauf.

    http://nougad.blogspot.com/2008/02/mono-funktional.html

    By nougad on Feb 13, 2008

  3. Das nenn ich übergreifendes Blogging:)! So muss das sein!

    Danke:) für die erste Lösung. Ich hoffe auf weitere Einreichungen ;)

    By Andi on Feb 13, 2008

  4. Ich hab auch endlich Zeit gefunden.
    http://aaron-mueller.de/blog/fsharp-tutorial2

    (Danke Flo für den Tipp mit der Version :)) Hab 10 Minuten lang rumgegrübelt warum denn die Funktion printfn nicht definiert sei, dabei hab ich mit einer Uraltversion von F# gearbeitet)

    By Aaron on Feb 13, 2008

Post a Comment