JoeCaml OCaml Konzepte: Grundlegende Konzepte - Funktionen

[weiter]

Funktionen in OCaml

Funktionen stellen den Hauptbestandteil aller Sprachkonstrukte funktionaler Sprachen dar.

Funktion

Eindeutige Zuordnungsvorschrift zwischen Argumenten und Resultat

Funktionen höherer Ordnung

Funktionen, die Funktionen als Parameter besitzen oder deren Wertebereich Funktionen enthält

In ML-Sprachfamilie:
  • Werte wie alle anderen Werte
  • Standardmäßig anonym
Syntax:
# fun p1 ... pn -> expr;;

Im Gegensatz zu den vordefinierten Operatoren (im Prinzip auch Funktionen), welche geklammert in Prefix- oder wie gewohnt in Infix-Notation geschrieben werden, deklariert man Funktionen in OCaml nach der aus der Mathematik stammenden Notation: x -> f(x).

Funktionen nehmen Argumente und liefern ein Resultat, aber sie haben keine Nebeneffekte (lässt man die Möglichkeiten der imperativen Sprachkonstrukte von OCaml wie Manipulation von Datenstrukturen ect. ausser acht.).
Funktionsparameter, sowie auch Funktionsresultate sind strukturiert und typisiert.
Funktionen können selbst Argumente oder Resultate sein, sowie beliebig innerhalb Funktionskompositionen miteinander kombiniert werden.
Auuserdem lassen sich Funktionen zu generischen Funktionen gruppieren, wenn eine Sprache wie OCaml die Möglichkeit bietet, Funktionen als Argumente zu übergeben.
Funktionen werden im funktionalen Sprachgebrauch auch als "First-Class-Citizens" bezeichnet, was bedeutet, daß Funktionen manipuliert werden können wie andere Variablen auch.


[weiter]

Vergleich:
Bindungsmechanismus
Variablen

# let name = expr1 in expr2;;


Bindungsmechanismus
Funktionen

# ( fun x -> expr2 ) (expr1);;

Bei einem Vergleich des Bindungsmechanismus bei der Variablenbindung und Funktionsbindung ist zu erkennen, daß beide Formen nach den Auswertungsregeln äquivalent sind.


[weiter]

Beispiel:
Ein-Argument-Funktion

# let incr = fun i -> i + 1;;

val incr : int -> int = <fun>


Mehr-Argument-Funktion

# let sum = fun i j -> i + j;;

val sum : int -> int -> int = <fun>

Der Pfeil für einen Funktionstypen ist rechts assoziativ, d.h. int -> (int -> int).
Die Funktion sum ist also eine Funktion mit einem int-Argument, die eine Funktion mit einem anderen int-Argument liefert, welche einen int-Wert zurückgibt.
Dies wiederum bedeutet, daß alle Mehrargumentfunktionen als geschachtelte Funktionen implementiert sind.
Dieses Prinzip nennt man Currying, nach Haskell Curry.
Da die Funktion sum eigentlich eine Funktion als Resultat liefert, handelt es sich bei dieser Funktion bereits um eine Funktion höherer Ordnung. Curried-Funktionen, also alle Mehrargumentfunktionen beschreiben die einfachste Form einer Funktion höherer Ordnung.
Die explizite Curried-Form von sum ist demnach äquivalent zu obiger Deklaration.


[weiter]

Beispiel:
Explizite Curried-Form

# let sum = ( fun i -> ( fun j -> i + j ));;

val sum : int -> int -> int = <fun>


[weiter]

Beispiel:
Partielle Applikation

# let incr = sum 1;;

# incr (incr 1);;

Funktionen in OCaml können auch nur partiell appliziert werden.
Eine Partielle Applikation ist eine Funktionsanwendung auf ein oder mehrere aber nicht alle Argumente einer Funktion.
Die redifinierte Fassung von incr als teilweise Anwendung von sum liefert eine Funktion, welche noch eine Ganzzahl erwartet, um mit der Berechnung fortzufahren. In dieser Form kann man sehr schön geschachtelte Ausdrücke formulieren, für fortschreitende bzw zurückschreitende Berechnungsvorschriften (z.B. pred/succ, incr/decr, ...).


Beispiel:
Funktion höherer Ordnung

# let square x = x *. x;;

val square : float -> float = <fun>


Rechtsassoziativität !


# let derive f dx x =
((f (x +. dx) -. f x ) /. dx);;

val derive : (float -> float) ->
float -> float -> float = <fun>

Als naheliegendes Beispiel für Funktionen höherer Ordnung sei an dieser Stelle die Ableitung einer mathematischen Funktion genannt.
Die Ableitungsfunktion (derive) bildet eine einfache Funktion (square) auf eine neue Funktion ab.
Zu beachten ist wieder die Rechtsassoziativität des Funktionstypen: (float -> float) -> (float -> (float -> float)).
Die Funktion derive ist demnach eine Funktion die eine Funktion als Argument erwartet, die abzuleitende mathematische Funktion (float -> float), und eine Funktion liefert die ein weiteres Argument (delta dx) erwartet und als Resultat eine Funktion zurückgibt, die abgeleitete mathematische Funktion.



Hinweis:

"#" kennzeichnet Eingaben im OCaml Interpreter,
"val" bzw "- :" das Ergebnis der Auswertung und automatischen Typanalyse inkl. der vom System inferierten Typen.



[ Seminar "Programmierkonzepte und Programmiersprachen" ] [ Gliederung ] [ Grundlegende Konzepte ] [ Pattern Matching ]