- Anonymous (lambda) functions
- Partial function application and currying
- As-patterns
- Code reuse through composition
- Tips for writing readable code
- Space leaks and strict evaluation
- Avoiding space leaks with seq
- Learning to use seq
Anonymous (lambda) functions
1 2 3 4 5 6 7 8 9 10 | isInAny needle haystack = any inSequence haystack
where inSequence s = needle `isInfixOf` s
isInAny2 needle haystack = any (\s - > needle `isInfixOf` s) haystack
inc = \x - > x + 1
plus = \a b - > a + b
three = (\x - > x + 1 ) 2
|
- Durch Backslash eingeleitet (symbolisiert λ)
- Keine Guards erlaubt
- Vorsicht mit unvollständigen Patterns
- Oft schlechtere Lesbarkeit als z.B.
- lokale Funktionen mit
let
oder where
- Partial function application
- Sections
Partial function application and currying
- Alle Funktionen nehmen genau ein Argument
- Geben ggf. Funktion zurück, die das nächste Argument nimmt
- Parameterliste teilweise fixierbar
- Spezialisierte Funktion entsteht
1 2 3 4 5 6 7 8 | ghci> : type dropWhile
dropWhile :: (a - > Bool ) - > [a] - > [a]
ghci> : type dropWhile isSpace
dropWhile isSpace :: [Char] - > [Char]
ghci> map (dropWhile isSpace) [ " a" , "f" , " e" ]
[ "a" , "f" , "e" ]
|
- Nicht zu verwechseln mit partial functions
Partial function application and currying
1 2 3 4 5 | niceSum :: [Integer] - > Integer
niceSum xs = foldl ( + ) 0 xs
niceSum2 :: [Integer] - > Integer
niceSum2 = foldl ( + ) 0
|
Sections
- Spezialfall von Partial function application
- Geklammerte Schreibweise für infix Notation
- Linker oder rechter Operand fixierbar
1 2 3 4 5 6 7 8 9 10 11 | ghci> ( 1 + ) 2
3
ghci> map ( * 3 ) [ 24 , 36 ]
[ 72 , 108 ]
ghci> map ( 2 ^) [ 3 , 5 , 7 , 9 ]
[ 8 , 32 , 128 , 512 ]
ghci> : type elem
elem :: Eq a = > a - > [a] - > Bool
ghci> : type (`elem` [ 'a' .. 'z' ])
(`elem` [ 'a' .. 'z' ]) :: Char - > Bool
|
As-Patterns
- Pattern matching erlaubt Dekonstruieren von Listen
- Liste wird in Bestandteile zerlegt
- Problem: ursprüngliche Liste ist verloren
- Schlechte Lösung: Liste wieder zusammenbauen
- Gute Lösung: ursprünglicher Liste einen Namen geben
@
zwischen Name und Pattern
1 2 3 | suffixes :: [a] - > <a class = "internal" href = "/wiki/lernfp/a" >a< / a>
suffixes xs@(_:xs ') = xs : suffixes xs'
suffixes _ = []
|
Code reuse through composition
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | suffixes2 xs = init (tails xs)
compose f g x = f (g x)
suffixes3 xs = compose init tails xs
suffixes4 = compose init tails
(.) :: (b - > c) - > (a - > b) - > a - > c
suffixes5 = init . tails
capCount = length . filter (isUpper . head) . words
capCount "Hello there, Mom!" = = 2
|
(.)
ist rechtsassoziativ
- Kette von Funktionen wird rechts nach links angewandt
Tips for writing readable code
- Schleifen
- Welche Alternative bietet die beste Lesbarkeit?
- Komposition von Standardfunktionen
- fold
- Explizite Rekursion
- Anonyme Funktionen
- Bessere Alternativen:
- lokale Funktionen mit
let
oder where
- Partial function application / Sections
Space leaks and strict evaluation
- Welches
fold
für welche Anwendungsfälle?
foldr
für Erzeugen von Listen
foldl'
ansonsten
Avoiding space leaks with seq
1 2 3 4 5 6 | seq :: a - > t - > t
foldl' _ zero [] = zero
foldl' step zero (x:xs) =
let new = step zero x
in new `seq` foldl' step new xs
|
- erzwingt Evaluierung des ersten Arguments
- gibt das zweite Argument zurück
- Magie (nicht implementiert in Haskell)
Learning to use seq
seq
muss innerhalb eines Ausdrucks zuerst evaluiert werden
- sonst wird Ergebnis wieder in thunk verpackt
seq
hat keinen Effekt auf duplizierte Ausdrücke
- Fehlerhafte Beispiele:
1 2 3 4 5 6 7 8 | hiddenInside x y = someFunc (x `seq` y)
hiddenByLet x y z = let a = x `seq` someFunc y
in anotherFunc a z
badExpression step zero (x:xs) =
seq (step zero x)
(badExpression step (step zero x) xs)
|
Learning to use seq (II)
seq
verketten um mehrere Ausdrücke zu evaluieren:
1 | chained x y z = x `seq` y `seq` someFunc z
|
seq
stoppt bei Konstruktoren
- Workarounds für Listen, Tupel:
1 2 3 4 | strictPair (a,b) = a `seq` b `seq` (a,b)
strictList (x:xs) = x `seq` x : strictList xs
strictList [] = []
|
seq
ist kein Allheilmittel
Tests
- Hspec
- QuickCheck (Property-based testing)