Programmieren in Haskell

Werbung
Programmieren in Haskell
Syntax und Semantik von Haskell
Programmieren in Haskell
1
Was wir heute (und nächstes mal) machen
• Datentypdefinitionen
• Wertdefinitionen, Variablenbindungen
• Musterbindungen
• Funktionsbindungen
• Bewachte Gleichungen
• Lokale Definitionen mit where und let
• Gültigkeitsbereiche
• Fallunterscheidungen
• Syntaktischer Zucker / Kernsprache
Programmieren in Haskell
2
Datentypen, Datentypdefinitionen
data Instrument =
|
|
|
Oboe
HonkyTonkPiano
Cello
VoiceAahs
data Musik
Note Ton Dauer
Pause Dauer
Musik :*: Musik
Musik :+: Musik
Instr Instrument Musik
Tempo GanzeZahl Musik
Programmieren in Haskell
=
|
|
|
|
|
3
Wahrheitswerte
data Bool = False | True
Programmieren in Haskell
-- vordefiniert
4
Ganze Zahlen
data Ganz = Zero |
Succ Ganz
Zero, Succ Zero, Succ (Succ Zero), . . .
Eingebaute Datentypen: Int und Integer
Programmieren in Haskell
5
Tupeltypen
data Pair a b
= Pair a b
data Triple a b c = Triple a b c
Eingebaute Datentypen: (a,b), (a,b,c)
Programmieren in Haskell
6
Listen
data List a = Empty | Front a (List a)
Eingebauter Datentyp: [a]
Programmieren in Haskell
7
Allgemeine Form
data T a1 . . . am
Programmieren in Haskell
=
C1 t11 . . . t1n1
|
...
|
Cr tr1 . . . trnr
8
Allgemeine Form
data T a1 . . . am
=
C1 t11 . . . t1n1
|
...
|
Cr tr1 . . . trnr
T : Typkonstruktor; Ci : (Daten-)Konstruktoren; ai : Typvariablen; tij : Typen oder
Typvariablen
Programmieren in Haskell
8
Selektorfunktionen auf Tupeln
fst :: (a,b) -> a
fst (a,b) = a
-- vordefiniert
snd :: (a,b) -> b
snd (a,b) = b
-- vordefiniert
Programmieren in Haskell
9
Selektorfunktionen auf Listen
head :: [a] -> a
head (x:xs) = x
-- vordefiniert
tail :: [a] -> [a]
tail (x:xs) = xs
-- vordefiniert
Programmieren in Haskell
10
Selektorfunktionen auf Musik
ton :: Musik -> Int
ton (Note ton dauer) = ton
dauer :: Musik -> Rational
dauer (Note ton dauer) = dauer
dauer (Pause
dauer) = dauer
Programmieren in Haskell
11
Listen mit Field Labels
data List a = Empty | Front { head :: a, tail :: List a }
Dies definiert Selektorfunktionen head, tail.
Programmieren in Haskell
12
Musik mit Field Labels
data Musik =
|
|
|
|
|
Note
Pause
(:*:)
(:+:)
Instr
Tempo
{
{
{
{
{
{
ton :: Int, dauer :: Rational }
dauer :: Rational }
links :: Musik, rechts :: Musik
oben :: Musik, unten :: Musik
instrument :: Instrument, musik
tempo :: Int, musik :: Musik }
}
}
:: Musik }
deriving Show
Dies definiert Selektorfunktionen
ton, dauer, links, rechts, oben, unten, instrument, tempo.
Programmieren in Haskell
13
Typsynonyme
type GanzeZahl
type Bruch
= Int
= Rational
type Ton
type Dauer
= GanzeZahl
= Bruch
Programmieren in Haskell
14
Nutzen und Gefahren von Typsynonymen
type OrdList a = [a]
sort :: [a] -> OrdList a
Programmieren in Haskell
15
Nutzen und Gefahren von Typsynonymen
type OrdList a = [a]
sort :: [a] -> OrdList a
sort xs = xs
Typ ok?
Programmieren in Haskell
15
Nutzen und Gefahren von Typsynonymen
type OrdList a = [a]
sort :: [a] -> OrdList a
sort xs = xs
Typ ok? Ja
Programmieren in Haskell
15
Nutzen und Gefahren von Typsynonymen
type OrdList a = [a]
sort :: [a] -> OrdList a
sort xs = xs
Typ ok? Ja
Ergebnis geordnete Liste?
Programmieren in Haskell
15
Nutzen und Gefahren von Typsynonymen
type OrdList a = [a]
sort :: [a] -> OrdList a
sort xs = xs
Typ ok? Ja
Ergebnis geordnete Liste? Nein (jedenfalls nicht im allgemeinen)
Programmieren in Haskell
15
Newtype-Deklaration
newtype Natural = MakeNatural Integer deriving (Show,Eq)
toNatural :: Integer -> Natural
toNatural x | x < 0
= error "Can’t create negative naturals!"
| otherwise = MakeNatural x
fromNatural :: Natural -> Integer
fromNatural (MakeNatural i) = i
Programmieren in Haskell
16
instance Num Natural where
fromInteger = toNatural
x + y
= toNatural (fromNatural x + fromNatural y)
x - y
= let r = fromNatural x - fromNatural y in
if r < 0 then error "Unnatural subtraction"
else toNatural r
x * y
= toNatural (fromNatural x * fromNatural y)
Programmieren in Haskell
17
Wertdefinitionen, Variablenbindungen
theFinalAnswer :: Integer
theFinalAnswer = 42
aShortList :: [Integer]
aShortList = [1,2,3]
helloWorld :: String
helloWorld = "Hello World"
monotonie :: Musik
monotonie = c’ (1/1) :*: monotonie
Programmieren in Haskell
18
Musterbindungen
myList = Front 1 (Front 2 (Front 3 Empty))
Front x (Front y zs) = myList
(x:y:zs) = [1,2,3]
Allgemein: p = e, mit p Muster, e Ausdruck
Programmieren in Haskell
19
bruderJakob = Tempo andante
(einsatz (0/1)
(einsatz (2/1)
(einsatz (4/1)
(einsatz (6/1)
(Instr VoiceAahs
endlos
:+:
(transponiere 12 endlos)) :+:
endlos)
:+:
endlos )))
Tempo t (Instr i (m1 :+: m2 :+: m3:+: m4)) = bruderJakob
Programmieren in Haskell
20
Funktionsbindungen
length :: [a] -> Int
length []
= 0
length (a:as) = 1 + length as
Programmieren in Haskell
-- vordefiniert
21
Allgemeiner Fall
f p11 . . . p1n
=
e1
...
=
...
f pk1 . . . pkn
=
ek
pij : Muster, ei : Ausdrücke
Programmieren in Haskell
22
Bewachte Gleichungen
member :: (Ord a) => a -> OrdList a -> Bool
member a []
= False
member a (b:bs) = a >= b && (a == b || member a bs)
member a [] = False
member a (b:bs) = if a < b then False else if a == b then True else member a bs
member a []
member a (b:bs)
| a < b
| a == b
| a > b
Programmieren in Haskell
= False
= False
= True
= member a bs
23
Lokale Definitionen mit where
sumSquares :: Int -> Int -> Int
sumSquares x y = sqX + sqY where
sqX = x * x
sqY = y * y
Programmieren in Haskell
24
Lokale Definitionen mit let
sumSquares :: Int -> Int -> Int
sumSquares x y = let sqX = x * x
sqY = y * y
in sqX + sqY
Programmieren in Haskell
25
Gültigkeits- oder Sichtbarkeitsbereiche
f :: Int -> Int
f x = f (x+x)
where x
= 1
f x = x
Programmieren in Haskell
-- Negativ-Beispiel
26
Gültigkeits- oder Sichtbarkeitsbereiche
f :: Int -> Int
f x = f (x+x)
where x
= 1
f x = x
-- Negativ-Beispiel
f1 :: Int -> Int
f1 x1 = f2 (x2+x2)
where x2
= 1
f2 x3 = x3
Programmieren in Haskell
26
Abseitsregel
• Das erste Zeichen der Definition unmittelbar nach dem where bestimmt die
Einrücktiefe des neu eröffneten Definitionsblocks.
• Zeilen, die weiter als bis zu dieser Position eingerückt sind, gelten als
Fortsetzungen einer begonnenen lokalen Definition.
• Zeilen auf gleicher Einrücktiefe beginnen eine neue Definition im lokalen Block.
• Die erste geringer eingerückte Zeile beendet den lokalen Block.
Programmieren in Haskell
27
Fallunterscheidungen
length :: [a] -> Int
length []
= 0
length (a:as) = 1 + length as
-- vordefiniert
length’ :: [a] -> Int
length’ as = case as of
[]
-> 0
a:as’ -> 1 + length’ as’
last’ :: [a] -> a
last’ as = case reverse as of a:as’ -> a
Programmieren in Haskell
28
Allgemeine Form von Fallunterscheidungen
case e of { p1 m1 ; . . . ;pn mn }
Die pi sind beliebige Muster und die mi nehmen wahlweise eine der beiden
folgenden Formen an:
-> e where { d1 ; . . . ;dp }
oder
| g1 -> e1
...
| gq -> eq
where { d1 ; . . . ;dp }
Programmieren in Haskell
29
Funktionsausdrücke
Ist n + 1 ein Wert oder eine Funktion?
Als Funktion:
f n = n + 1
\n -> n + 1
Allgemeine Form eines Funktionsausdrucks:
\p1 . . . pn -> e .
\p1 p2 -> e als Abkürzung für \p1 -> \p2 -> e
Programmieren in Haskell
30
Gestaffelte Funktionen
add :: Integer -> Integer -> Integer
add m n = m + n
add’ :: Integer -> (Integer -> Integer)
add’ = \m -> \n -> m + n
Programmieren in Haskell
31
Gestaffelte Funktionen
add :: Integer -> Integer -> Integer
add m n = m + n
add’ :: Integer -> (Integer -> Integer)
add’ = \m -> \n -> m + n
Programmieren in Haskell
31
note :: Int -> Int -> Dauer -> Musik
note oct h d = Note (12 * oct + h) d
note Eine Note in einer beliebigen Oktave und von beliebiger Höhe und Dauer.
note 2 Eine Note in der dritten Oktave und von beliebiger Höhe und Dauer.
note 2 ef Die Note f in der dritten Oktave und von beliebiger Dauer.
note 2 ef (1/4) ergibt Note 29 (1/4).
Programmieren in Haskell
32
Syntaktischer Zucker / Kernsprache
• Mustergleichungen / case-Ausdrücke
length []
= 0
length (x:xs) = 1 + length xs
length’ xs = case xs of
[]
-> 0
(x:xs) -> 1 + length’ xs
• Funktionsdefinitionen / Funktions-Ausdrücke
add m n = m + n
add’ = \m -> \n -> m + n
Programmieren in Haskell
33
• where-Klauseln / let-Ausdrücke
double n = add0 (dup n) where
dup a = (a,a)
double n = let dup a = (a,a) in add0 (dup n)
Programmieren in Haskell
34
Auswertung von Fallunterscheidungen
case C e1 ...ek of {...; C x1 ...xk -> e;...}
(case-Regel)
⇒ e[x1 /e1 , . . . , xn /en ]
Programmieren in Haskell
35
abs :: (Ord a, Num a) => a -> a
abs n = case n >= 0 of
True -> n
False -> -n
encode :: (Num a) => Maybe a -> a
encode x = case x of
Nothing -> -1
Just n -> abs n
encode (Just 5)
⇒
case Just 5 of {Nothing -> -1; Just n -> abs n}
(Def. encode)
⇒
abs 5
(case − Regel)
⇒
case 5 >= 0 of {True -> 5; False -> -5}
(Def. abs)
⇒
case True of {True -> 5; False -> -5}
(Def. >=)
⇒
5
Programmieren in Haskell
(case − Regel)
36
Auswertung von Funktionsanwendungen
(\x -> e) a ⇒ e[x/a]
Programmieren in Haskell
(β-Regel)
(1)
37
abs
=
encode =
\n -> case n >= 0 of {True -> n; False -> -n}
\x -> case x of {Nothing -> -1; Just n -> abs n}
encode (Just 5)
(Def. encode)
⇒
(\x-> case x of {Nothing-> -1; Just n-> abs n}) (Just 5)
⇒
case Just 5 of {Nothing -> -1; Just n -> abs n}
⇒
abs 5
⇒
(\n -> case n >= 0 of {True -> n; False -> -n}) 5
(Def. abs)
⇒
case 5 >= 0 of {True -> 5; False -> -5}
(β − Regel)
⇒
case True of {True -> 5; False -> -5}
(Def. (>=))
⇒
5
Programmieren in Haskell
(β − Regel)
(case − Regel)
(case − Regel)
38
Auswertung von lokalen Definitionen
let {x1 = e1 ;...;xn = en } in e
⇒ e[x1 /let {x1 = e1 ;...;xn = en } in e1 , . . . ,
(let-Regel)
xn /let {x1 = e1 ;...;xn = en } in en ]
Programmieren in Haskell
39
rep n a = let x = a:x in take n x
rep 2 8
Programmieren in Haskell
⇒
let x = 8:x in take 2 x
⇒
take 2 (let x = 8:x in 8:x)
(let − Regel)
⇒
take 2 (8:let x = 8:x in 8:x)
(let − Regel)
⇒
8:take 1 (let x = 8:x in 8:x)
(Def. take)
⇒
8:take 1 (8:let x = 8:x in 8:x)
(let − Regel)
⇒
8:8:take 0 (let x = 8:x in 8:x)
(Def. take)
⇒
8:8:[]
(Def. take)
(Def. rep)
40
Herunterladen