JoeCaml OCaml Konzepte: Grundlegende Konzepte - Polymorphismus

[weiter]

Polymorphismus in OCaml

Polymorphie ("Vielgestaltigkeit") ist ein wichtiges Konzept objektorientierter und funktionaler Sprachen.
Die unterschiedlichen Erscheinungsformen haben als gemeinsamen Nenner, daß allgemein ein Ausdruck für mehrere, unterschiedliche Typen definiert ist.

Polymorphismus In OO-Sprachen:
  • Ad hoc - Polymorphismus: Überladen von Methoden/Funktionen
  • Subtyppolymorphismus: Objekte, die den selben Vorfahren besitzen, teilen oder redefinieren gleiche Operationen
parametrischer Polymorphismus In ML-Sprachen:
  • Typparametrisierung implizit bei der Hindley-Milner Typüberprüfung
  • Typen können explizit mit Typvariablen parametrisiert werden
  • Polymorphe, generische Funktionen, Klassen, Module, ...
Typvariable

Platzhalter für beliebige Typen

Let-bound Polymorphismus
  • Restriktion im Hindley-Milner Typsystem
  • Polymorphismus ist beschränkt auf Werte

Man unterscheidet im Allgemeinen zwischen parametrischer und Ad-hoc-Polymorphie.
Parametrische Polymorphie liegt vor, wenn Funktionen gleichartig auf einer ganzen Klasse von Datenobjekten wirken.
Typisch für die Ad-hoc-Polymorphie objektorientierter Sprachen sind überladene Operatoren wie z.B. die arithmetischen Funktionen, die für Ganzzahlen und Gleitkommazahlen definiert sind, oder die Gleichheitsfunktion, die für unterschiedliche Typen unterschiedlich definiert werden muss, aber dennoch eine feste Semantik besitzt. Hier steht dasselbe Symbol für eine Reihe von unterschiedlichen Funktionen, von denen je nach Kontext die passende ausgewählt wird.
Das Hindley/Milner-Typsystem unterstützt nur die parametrische Polymorphie, die in der ML-Sprachfamilie durch die Let-Bindung und Restriktionen, welche sich aus den nachteiligen Effekten der imperativen Sprachkonstrukte ergeben, eingeschränkt wird.

Die Interaktion zwischen Polymorphismus und Seiteneffekten der imperativen Konstrukte in der ML-Sprachfamilie stellt allerdings seit jeher ein ärgerliches Problem dar.


[weiter]

Beispiel:
Polymorphe Funktion

# let identity x = x;;

val identity : 'a -> 'a = <fun>


# identity 1;;

- : int = 1


# identity "Hello";;

- : string = "Hello"

Die inferierte Typvariable 'a bezeichnet einen sogenannten Typparameter und lässt die Funktion identity offen für beliebige Datentypen.
Die Funktion identity erwartet also einen Wert beliebigen Typs und liefert genau diesen zurück.
Generell sind Funktionen in OCaml, welche lediglich Werte umkopieren (Komposition und Dekomposition von eigenen Datentypen) oder relationale Operatoren verwenden polymorph, also für beliebige Typen anwendbar.


[weiter]

Polymorphismus ist beschränkt auf Werte !

Beispiel:
Partielle Applikation

# let identity' = identity identity;;

val identity : '_a -> '_a = <fun>


# identity' 1;;

- : int = 1


# identity';;

- : int -> int = <fun>

Die Typvariable '_a ist kein Typparameter, sondern ein unbekannter Typ, welcher auf eine Wertzuweisung (Instanzierung) wartet.
Danach ist der Typ der Variablen '_a auf den Typen des zugewiesenen Wertes permanent festgelegt.
Eine Lösung für diese Problematik ist die Eta-Expansion, d.h. die explizite Angabe von Argumenten.

[weiter]

Werte

  • Funktionen
  • Konstanten
  • Konstruktoren unveränderlicher Werte
Keine Werte

  • Funktionapplikationen
  • Kontrollstrukturen: z.B. Pattern Matching
  • Konstruktoren von Typen mit veränderlichen Werten

[weiter]

Lösung durch explizite Angabe von Argumenten !

Beispiel:
Eta-Expansion

# let identity' x = ( identity identity) x;;

val identity' : 'a -> 'a = <fun>

Durch die explizite Angabe des Parameters x und entsprechender Klammerung erhält man wieder eine polymorphe Form der Funktion.


[weiter]

Beispiel:
Overloading in Java

class Adder {
static int Add (int i , int j){
return i + j;
}
static float Add (float i , float j){
return i + j;
}
}

Der Plus-Operator (+) ist beispielsweise in Java überladen für Ganzzahlen, Fließkommazahlen, sogar für Zeichenketten, wo er die Konkatenation repräsentiert. Jedoch fordert der Ad-hoc Polymorphismus eine eindeutige Angabe (hier durch die explizite Festlegung der Parametertypen) zur Auswahl der entsprechenden Methode und Kompilierung des/der entsprechenden Maschinenbefehle zur Berechnung. Im Gegensatz zu Java unterstützt OCaml kein Überladen von Funktionen und Methoden.


Annahme:

Plus-Operator (+) überladen für int und float


# let add x y = x + y;;

Typ der Funktion ?
val add : int -> int -> int
oder
val add : float -> float -> float

OCaml unterstützt kein Überladen von Methoden und Funktionen, da für den Mechanismus der Typinferenz unentscheidbare Situationen (vor allem auch durch Seiteneffekte) nicht ausgeschlossen werden können.



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 ] [ Produkttypen in OCaml ]