home Funktionale Programmierung: Begriffe, Definitionen und grundlegende Konzepte Prof. Dr. Uwe Schmidt FH Wedel

Begriffe, Definitionen und grundlegende Konzepte

weiter

weiter

Funktionale Programmierung

Charakteristische Begriffe
Funktion
Funktionsanwendung
Typ
Ausdruck
Wert
weiter
nicht
Zuweisung
Schleife
Prozedur
Objekt
Methode
weiter
Auswertung
den durch einem Ausdruck beschriebenen Wert berechnen
weiter
Funktion
wie in der Mathematik:
eindeutige Zuordnung eines Resultats zu einem Argument
Beschreibung der Beziehung zwischen Werten
weiter
Typ
Beschreibung für eine Menge von Werten
Werteart
anschauliche Sichtweise, in der Theorie etwas zu einfach
weiter
ungetypte Sprache
nur eine universelle Werteart
 
LISP
Listen, genauer Bäume
Tcl
Strings, Zeichenreihen
Java
Object
weiter
getypte Sprache
viele verschiedene Wertearten
weiter
statisch getype Sprache
oder streng getypte Sprache:
die Werteart aller Variablen, Konstanten und Ausdrücke wird vollständig statisch (zur Übersetzungszeit) bestimmt
weiter
Parametertyp
Wertebereich der zulässigen aktuellen Parameter einer Funktion
weiter
Resultattyp
Wertebereich der Resultatwerte einer Funktion
weiter
Werte
Zahlen, Zeichen, Listen, Bilder, Programme, ...
 
0, 1, 2
1.0, 4.2
'a', 'b', 'c'
"", "abc", "123"
(1, "abc")
[], ["a"], [1, 2, 3]
weiter
Wertedefinition
besteht aus zwei Teilen
 
  • Name für einen Ausdruck
  • Typ des Ausdrucks
weiter
Syntax
name :: Typ
name =  expr
weiter
Beispiel
 
dieZahl :: Integer
dieZahl =  6 * (+ 4)
weiter
::
besitzt den Typ
weiter
=
wird definiert durch
nicht Gleichheitstest (==)
weiter
Konvention
Teil der Sprachdefinition
weiter
Wertenamen
beginnen mit Kleinbuchstaben
weiter
Typnamen
beginnen mit Großbuchstaben
 
Int, Integer,
Char, String,
Maybe, Either
weiter
Funktionsdefinition
für Funktionen mit einem Parameter
 
fct     :: ArgType -> ResultType
fct x   =  expr
Beispiel
square          :: Integer -> Integer
square x        = x * x
 
smaller         :: (Integer, Integer) -> Integer
smaller (x,y)   = if x <= y then x else y
weiter
Anwendung
Aufruf einer Funktion
 
square 5
square (+ 4)
square (smaller (5, 3 + 4))
weiter
Auswertung
Vereinfachung
Reduktion
Ersetzen der linken Seite durch die rechte Seite und rechnen (reduzieren, vereinfachen, auswerten)
weiter
Beispiel
  square (3 + 4)
={ Definition von + }
  square 7
={ Definition von square }
  7 * 7
={ Definition von * }
  49
weiter
merke
Auswertung von innen nach außen
merke
innermost leftmost
merke
call by value
weiter
2. Beispiel
  square (3 + 4)
={ Definition von square }
  (3 + 4) * (3 + 4)
={ Definition von + im linken Teilausdruck von * }
  7 * (3 + 4)
={ Definition von + im rechten Teilausdruck von * }
  7 * 7
={ Definition von * }
  49
weiter
merke
Auswertung von außen nach innen
merke
outermost leftmost
merke
call by name
weiter
3. Beispiel
  square (3 + 4)
={ Definition von square }
  x * x where x = 3 + 4
={ Definition von + im Teilausdruck }
  x * x where x = 7
={ Einsetzen von x }
  7 * 7
={ Definition von * }
  49
weiter
merke
Ersetzen von außen nach innen
merke
Bedarfsauswertung, lazy evaluation
merke
call by need
merke
wie 2. nur keine doppelten Auswertungen
weiter
?
Welches ist die beste Strategie?
weiter
Auswertungsreihenfolge
2. Beispiel
 
three           :: Integer -> Integer
three x         =  3
 
infinity        :: Integer
infinity        =  infinity + 1
weiter
call by value
von innen nach außen
 
  three infinity
={ Definition von infinity }
  three (infinity + 1)
={ Definition von infinity }
  three ((infinity + 1) + 1)
={ Definition von infinity }
  three (((infinity + 1) + 1) + 1)
={ und so weiter }
  ...
schlecht
Die Berechnung terminiert nicht,
sie divergiert
weiter
call by name
von außen nach innen
 
  three infinity
={ Definition von three }
  3
weiter
bottom
undefinierter Wert:
 
Jeder Wertebereich enthält (in der Theorie) einen zusätzlichen undefinierten Wert
weiter
.1
für illegale Argumente
Beispiel
 1/0
 
Abbruch des Programms mit einer Fehlermeldung
weiter
.2
für nichtterminierende Berechnungen
Beispiel
infinity
 
Endlos-Rekursion, Endlos-Schleife
weiter
merke
.1 ist feststellbar,
.2 nicht
weiter
merke
1. Beispiel mit unterschiedlichen Semantiken bei unterschiedlichen Auswertungsstrategien
weiter
Auswertungsreihenfolge
3. Beispiel
multiply        :: (Integer, Integer) -> Integer
multiply (x, y) =  if x == 0 then 0 else x * y
 
-- 2 Aufrufe
 
multiply (0, infinity)
multiply (infinity, 0)
weiter
Definition: strikt
eine Funktion f ist genau dann strikt, wenn f  =  gilt, sonst ist f nicht strikt.
weiter
Extensionalitäts-
Prinzip
extensionality

zwei Funktionen f und g sind genau dann gleich, wenn für alle Argumente x gilt: f x = g x

Beispiel
double, double2 :: Integer -> Integer
 
double  x       =  x + x
double2 x       =  2 * x
 
double x = double2 x        -- für alle x
double   = double2
weiter
merke
dieses Problem ist unentscheidbar
merke
=> keine Gleichheitstest für Funktionen definiert
weiter
Funktionsdefinition
für Funktionen mit mehreren Parametern
weiter
Currying
Beispiel .a
smaller         :: (Integer, Integer) -> Integer
smaller (x, y)  =  if x <= y then x else y
weiter
merke
ein Parameter bestehend aus einem Paar ganzer Zahlen
weiter
Beispiel .b
smallerc        :: Integer -> (Integer -> Integer)
smallerc x y    =  if x <= y then x else y
weiter
merke
zwei Parameter
weiter
Aufruf
smallerc a      :: Integer -> Integer
(smallerc a) b  :: Integer
 
-- gleichwertig mit
 
smallerc a b
weiter
gut
Currying: Weniger Klammern
gut
Currying: Parameter können zu unterschiedlichen Zeitpunkten übergeben werden
weiter
Beispiel
plus            :: (Integer, Integer) -> Integer
plus (x, y)     = x + y
 
incr            :: Integer -> Integer
incr y          = plus (1, y)
 
plusc           :: Integer -> (Integer -> Integer)
plusc x y       = x + y
 
incrc           :: Integer -> Integer
incrc           = plusc 1
 
-- Aufruf
 
incrc 41
weiter
2. Beispiel
twice           :: (Integer -> Integer) ->
                   (Integer -> Integer)
twice f x       = f (f x)
 
quad            :: Integer -> Integer
quad            = twice square
 
-- ohne Currying
 
twice           :: (Integer -> Integer, Integer) ->
                   Integer
twice (f, x)    = f (f x)
 
quad            :: Integer -> Integer
quad x          = twice (square, x)
weiter
NICHT
quad x = twice (square, x) -- für alle x
weiter
SONDERN
quad = twice square
weiter
Konversion
uncurried => curried
 
curry           :: ((a, b) -> c) -> (a -> b -> c)
curry f x y     = f (x, y)
Konversion
curried => uncurried
 
uncurry          :: (a -> b -> c) -> ((a, b) -> c)
uncurry f (x, y) = f x y
merke
Signatur mit Typparametern
weiter
Assoziatvität
des Funktionspfeils ->
 
  a -> (b -> c)
={ Rechtsassoziativität von -> }
  a -> b -> c
weiter
Funktionen mit mehreren Parametern
 
fct              :: t1 -> t2 -> ... -> tn -> t
fct x1 x2 ... xn =  <expr>
 
-- Aufruf
 
fct e1 e2 ... en
weiter
2-stellige Operatoren
sind Funktionen mit 2 Parametern in Infix-Notation
 
+ 4    entspricht  plusc 3 4
+ 4    entspricht  (+) 3 4
 
-- Definition von plusc
 
plusc = (+)
weiter
Funktionskomposition
  • zusammensetzen von Funktionen
  • kombinieren --> Kombinatoren
weiter
gegeben
f1 :: t1 -> t2
f2 :: t2 -> t3
weiter
Komposition
(f2 . f1) x = f2 (f1 x)
 
-- oder
 
(.) f2 f1 x = f2 (f1 x)
weiter
Typ
(.) :: (t2 -> t3) -> (t1 -> t2) -> (t1 -> t3)
weiter
Folgerung
quad    :: Integer -> Integer
quad    =  square . square
 
-- anstatt
 
quad x  = square (square x)
weiter
point-free style
quad = square . square
weiter
point-wise style
quad x = square (square x)
weiter
merke
Funktionskomposition gibt es in (traditionellen) imperativen Programmiersprachen nicht
weiter
?
Ausnahme?
weiter
Assoziativität
  (f . g) . h
={ Assoziativität der Komposition }
  f . (g . h)
={ Klammern redundant }
  f . g . h
weiter
Komposition
von links nach rechts gelesen
 
(>>>)     ::  (t1 -> t2) -> (t2 -> t3) -> (t1 -> t3)
f1 >>> f2 = f2 . f1
weiter
guards
Wächter
signum          :: Integer -> Integer
signum x
  | x <  0      = -1
  | x == 0      =  0
  | x >  0      =  1
 
-- gleichwertig zu
 
signum          :: Integer -> Integer
signum x        = if x < 0
                  then -1
                  else if x == 0
                       then 0
                       else 1
weiter
Rekursion
fact            :: Integer -> Integer
fact n          =  if n == 0
                   then 1
                   else n * fact (n - 1)
 
-- oder
 
fact n
  | n == 0      = 1
  | otherwise   = n * fact (n - 1)

besser

fact            :: Integer -> Integer
 
fact n
  | n == 0   = 1
  | n > 0    = n * fact (n - 1)
  | n < 0    = error "fact with negative argument"
weiter
Definition
lokaler Größen
 
f       :: Float -> Float -> Float
f x y   = (a + 1) * (a + 2)
          where
          a = (x + y) / 2
 
f2      :: Float -> Float -> Float
f2 x y  = (a + 1) * (b + 2)
          where
          a = m / 2
          b = m / 3
          m = x + y
weiter
Polymorphe Typen
square          :: Integer -> Integer
sqrt            :: Integer -> Float
 
-- also
 
square . square :: Integer -> Integer
sqrt . square   :: Integer -> Float
?
Wiederholung: Welchen Typ besitzt .?
weiter
merke
a, b und c sind Typvariablen
Definition
Typen, die eine Typvariable enthalten, heißen polymophe Typen
weiter
Namenskonvention
Typvariablen beginnen mit einem Kleinbuchstaben
weiter
Beispiele
curry     :: ((a,b) -> c) -> (a -> b -> c)
 
error     :: String -> a
 
id        :: a -> a
 
undefined :: a
 
-- für alle Typen a, b und c
weiter
?
Definition des Wertes undefined?
weiter
Typklassen
(+)     :: Int -> Int -> Int
(+)     :: Integer -> Integer -> Integer
(+)     :: Float -> Float -> Float
(+)     :: ...
 
-- also (???)
 
(+)     :: a -> a -> a
weiter
merke
Beliebige Typen a ist zu allgemein
weiter
Lösung
Typklassen
 
Typen, die eine bestimmte zusätzliche Eigenschaft besitzen
 
(+)     :: Num a => a -> a -> a
weiter
merke
verschiedene vordefinierte Typklassen: für Gleichheitstests, Ordnung, Arithmetik, Konversion in eine externe Darstellung, ...
weiter
dieser Seite als Haskell-Quelle

Letzte Änderung: 16.04.2012
© Prof. Dr. Uwe Schmidt
Prof. Dr. Uwe Schmidt FH Wedel