VL06: Haskell (Funktionen höherer Ordnung, Currying)

IFM 5.3 Spezielle Methoden der Programmierung

Carsten Gips, FH Bielefeld

18.05.2015

Wiederholung

Wiederholung

Wie können Sie die ersten n Elemente einer Liste auswählen?

Wie können Sie die ersten n Elemente einer Liste entfernen?

Was sind “List Comprehensions”?

Was ist der Unterschied zwischen den beiden folgenden Aufrufen?

zip [1 .. 5] ["one", "two", "three"]
[(x, y) | x <- [1 .. 5], y <- ["one", "two", "three"]]

Was bedeutet “Pattern Matching” im Zusammenhang mit der Funktionsdefinition?

Motivation

Themen für heute

Am Ende der VL können/verstehen Sie:

Funktionen mit Guards und where definieren

Currying und partiell angewendete Funktionen

Funktionen höherer Ordnung: Faltungen, Map, Filter, Lambda-Ausdrücke

Mindmap

Weitere Formen der Funktionsdefinition

Guards, guards!

bmi gewicht groesse
    | gewicht / groesse^2 <= 18.5   = "Spacko"
    | gewicht / groesse^2 <= 25.0   = "Normalo"
    | gewicht / groesse^2 <= 30.0   = "Untergross"
    | otherwise                     = "Autsch"

Pattern Matching: Parameter passt zu Form (Destruktion)

Guards: Lesbare Form eines if-Statements

=> Wichtig: Letzter Fall immer mit otherwise

ghci :l bmi.hs

Verbesserung von bmi

Was stört Sie an dieser Version von bmi?

bmicalc gewicht groesse
    | gewicht / groesse^2 <= 18.5 = "Spacko"
    | gewicht / groesse^2 <= 25.0 = "Normalo"
    | gewicht / groesse^2 <= 30.0 = "Untergross"
    | otherwise                   = "Garfield"

Where!?

bmicalc gewicht groesse
    | bmi <= 18.5 = "Spacko"
    | bmi <= 25.0 = "Normalo"
    | bmi <= 30.0 = "Untergross"
    | otherwise   = "Garfield"
    where bmi = gewicht / groesse^2

=> Zusammenfassung der Berechnung in lokaler Variable

Where!? (cnt.)

bmicalc gewicht groesse
    | bmi <= skinny = "Spacko"
    | bmi <= normal = "Normalo"
    | bmi <= fat    = "Untergross"
    | otherwise     = "Garfield"
    where bmi = gewicht / groesse^2
          skinny = 18.5
          normal = 25.0
          fat    = 30.0

=> Einrückung wichtig!

List Comprehensions (Listenverarbeitung)

S={2*x∣x∈N,x≤10}

[x*2 | x <- [1..10]]

Prelude> [x*2 | x <- [1..10], x*2>5]

Prelude> let xs = ["A", "B", "C"]
Prelude> [a ++ "-" ++ b | a <- xs, b <- xs]
Prelude> [a ++ "-" ++ b | a <- xs, b <- xs, a < b]

Prelude> [(a,b) | a <- [1..3], b <- [1..a]]

List Comprehensions ergeben eine Liste

Linke Seite: Ausdruck, der zum Bilden der Listenelemente genutzt wird

Rechte Seite:

Generatoren: a <- xs bedeutet “Nimm der Reihe nach alle Elemente aus xs und binde sie an a”

Filter: Prädikate, die erfüllt sein müssen, damit das aktuell betrachtete Element aus dem Generator in die Ergebnisliste übernommen wird

Pattern Matching funktioniert auch in List Comprehensions: [a+b | (a,b) <- xs]

ghci

Beispiel zipWith-Funktion

Eingabe: Funktion f, zwei Listen

Rückgabe: Liste

Arbeitsweise: Fügt die Listen zusammen, indem für die korrespondierenden Elemente jeweils die Funktion f aufgerufen wird

Signatur?

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]

Definition?

zipWith _ [] _ = []
zipWith _ _ [] = []
zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys

Anwendung:

Prelude> zipWith (+) [4,2,5,6] [2,6,2,3]
Prelude> zipWith max [6,3,2,1] [7,3,1,5]

ghci

Berechnung der Aktivierung von Neuron aj

Aktivierung von Neuron aj:

aj={1falls w0,j+a1w1,j+a2w2,j+...+anwn,j≥00falls w0,j+a1w1,j+a2w2,j+...+anwn,j<0﻿

Zusammenfassung

Was haben Sie heute gehört?

Funktionsdefinition mit Guards, mit Where-Bindings und Let-in

Funktionen haben in Haskell genau einen Parameter

Currying: Partielle Anwendung einer Funktion auf einen Parameter liefert Funktion mit restlichen Parametern

Funktionskomposition mit .

Funktionen höherer Ordnung: Funktionen als Parameter oder Rückgabe

=> Beispiele: map, filter, foldl (“reduce”)

Anonyme Funktionen mit Lambda-Ausdrücken

Nächste Woche: Haskell (Typen und Typklassen)

Literatur zum Weiterlesen

Miran Lipovaca: “Learn You a Haskell for Great Good!”, learnyouahaskell.com

O’Sullivan, Stewart, Goerzen: “Real World Haskell”, book.realworldhaskell.org

Bruce A. Tate: “Seven Languages in Seven Weeks”, Pragmatic Bookshelf Inc., 2010

Haskell: Kapitel 8

Block, Neumann: “Haskell Intensivkurs”, Springer, 2011

Lernziele – Nach dieser Vorlesung sollten Sie …

Verstehen (K2)

Funktionen haben in Haskell einen Parameter

Prinzip des Currying (schrittweise partielle Applikation)

Signatur von Funktionen höherer Ordnung

Currying oft lesbarer als Lambda-Ausdrücke

Anwenden (K3)

Funktionsdefinition mit Guards und Pattern Matching

Nutzung von Where-Bindings und Let-in

Komposition von Funktionen mit .

Umgang mit map, filter, foldl, zip, …

Nutzung von Lambda-Ausdrücken

Diese Fragen sollten Sie beantworten können …

Worin besteht der Unterschied zwischen Guards und Pattern Matching?

Worin besteht der Unterschied zwischen Where-Bindings und Let-in-Ausdrücken?

Erklären Sie Currying an einem Beispiel. Worin liegt die praktische Bedeutung von partieller Applikation?

Was sind Lambda-Ausdrücke?

Diese Fragen sollten Sie beantworten können …

Erklären Sie foldl an einem Beispiel.

Was bedeuten die folgenden Code-Schnipsel?

map (+ 1) [1, 2, 3]
filter odd [1, 2, 3, 4, 5]
foldl1 (+) 0 [1 .. 3]

Diese Fragen sollten Sie beantworten können …

Schreiben Sie im folgenden Code-Schnipsel fibNth mit Hilfe von Funktionskomposition um:

lazyFib x y = x:(lazyFib y (x + y))
fib = lazyFib 1 1
fibNth x = head (drop (x - 1) (take (x) fib))

Definieren Sie eine Funktion fib5th durch partielle Applikation.