Kapitel 3: Eine einfache Programmiersprache

Werbung
Kapitel 3: Eine einfache Programmiersprache
Programmieren in Haskell
1
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
=
|
|
|
|
|
2
Allgemeine Form
data T a1 . . . am
Programmieren in Haskell
=
C1 t11 . . . t1n1
|
...
|
Cr tr1 . . . trnr
3
Wahrheitswerte
data Bool = False | True
Programmieren in Haskell
-- vordefiniert
4
Wahrheitswerte
data Bool = False | True
-- vordefiniert
not :: Bool -> Bool
-- vordefiniert
Programmieren in Haskell
4
Wahrheitswerte
data Bool = False | True
-- vordefiniert
not :: Bool -> Bool
not True = False
not False = True
-- vordefiniert
Programmieren in Haskell
4
Wahrheitswerte
data Bool = False | True
-- vordefiniert
not :: Bool -> Bool
not True = False
not False = True
-- vordefiniert
(&&), (||) :: Bool -> Bool -> Bool
-- vordefiniert
Programmieren in Haskell
4
Wahrheitswerte
data Bool = False | True
-- vordefiniert
not :: Bool -> Bool
not True = False
not False = True
-- vordefiniert
(&&), (||) :: Bool -> Bool -> Bool
False && y = False
True && y = y
-- vordefiniert
Programmieren in Haskell
4
Wahrheitswerte
data Bool = False | True
-- vordefiniert
not :: Bool -> Bool
not True = False
not False = True
-- vordefiniert
(&&),
False
True
True
False
-- vordefiniert
(||)
&& y
&& y
|| y
|| y
Programmieren in Haskell
:: Bool -> Bool -> Bool
= False
= y
= True
= y
4
Wahrheitswerte
data Bool = False | True
-- vordefiniert
not :: Bool -> Bool
not True = False
not False = True
-- vordefiniert
(&&),
False
True
True
False
-- vordefiniert
(||)
&& y
&& y
|| y
|| y
:: Bool -> Bool -> Bool
= False
= y
= True
= y
ifThenElse :: Bool -> a -> a -> a
ifThenElse True a a’ = a
ifThenElse False a a’ = a’
Mixfix-Notation: if x >= 0 then x else -x
Programmieren in Haskell
4
Ganze Zahlen
data Ganz = Zero |
Succ Ganz
Zero, Succ Zero, Succ (Succ Zero), . . .
Eingebaute Datentypen: Int und Integer
Operatoren: (+), (-), (*), div, mod, (^)
Programmieren in Haskell
5
Tupeltypen
data Pair a b
= Pair a b
data Triple a b c = Triple a b c
Abkürzende Schreibweise: (x,y), (x,y,z)
Selektorfunktionen:
fst :: (a,b) -> a
fst (a,b) = a
-- vordefiniert
snd :: (a,b) -> b
snd (a,b) = b
-- vordefiniert
Programmieren in Haskell
6
Listen
data List a = Empty | Front a (List a)
Eingebaute Listen: [a] statt List a, [] statt Empty , (x:xs) statt Front x xs
Abkürzende Schreibweise: [x,y,z] statt (x:y:z:[])
Programmieren in Haskell
7
Funktionen auf Listen
(++) :: [a] -> [a] -> [a]
[]
++ bs = bs
(a:as) ++ bs = a:(as++bs)
head :: [a] -> a
head (a:as) = a
tail :: [a] -> [a]
tail (a:as) = as
reverse :: [a] -> [a]
reverse []
= []
reverse (a:as)= reverse as ++ [a]
Programmieren in Haskell
8
Der Typ Maybe
data Maybe a = Nothing | Just a
-- vordefiniert
minimum1 :: [Integer] -> Integer
minimum1 [a]
= a
minimum1 (a:as) = min a (minimum1 as)
minimum0 :: [Integer] -> Maybe Integer
minimum0 []
= Nothing
minimum0 (a:as) = Just (minimum1 (a:as))
Programmieren in Haskell
9
Zeichen und Zeichenketten
data Char
= ... | ’0’ | ’1’ ...
| ... | ’A’ | ’B’ ...
| ... | ’a’ | ’b’ ...
-- Pseudo-Haskell
type String = [Char]
Abkürzende Schreibweise: "Marvin" statt [’M’,’a’,’r’,’v’,’i’,’n’], "" statt
[]
isSpace :: Char -> Bool
isSpace c = c == ’ ’ || c == ’\t’ || c == ’\n’ ||
c == ’\r’ || c == ’\f’ || c == ’\v’
Programmieren in Haskell
10
Typsynonyme
Schon gesehen: Ton, Dauer, DNA, Protein, String
Nutzen und Gefahren:
type OrdList a = [a]
merge :: OrdList a -> OrdList a -> OrdList a
merge xs ys = xs ++ ys
Typ ok?
Programmieren in Haskell
11
Typsynonyme
Schon gesehen: Ton, Dauer, DNA, Protein, String
Nutzen und Gefahren:
type OrdList a = [a]
merge :: OrdList a -> OrdList a -> OrdList a
merge xs ys = xs ++ ys
Typ ok? Ja
Programmieren in Haskell
11
Typsynonyme
Schon gesehen: Ton, Dauer, DNA, Protein, String
Nutzen und Gefahren:
type OrdList a = [a]
merge :: OrdList a -> OrdList a -> OrdList a
merge xs ys = xs ++ ys
Typ ok? Ja
Ergebnis geordnete Liste?
Programmieren in Haskell
11
Typsynonyme
Schon gesehen: Ton, Dauer, DNA, Protein, String
Nutzen und Gefahren:
type OrdList a = [a]
merge :: OrdList a -> OrdList a -> OrdList a
merge xs ys = xs ++ ys
Typ ok? Ja
Ergebnis geordnete Liste? Nein
Programmieren in Haskell
11
Typdeklarationen, Typprüfung und Typinferenz
map f []
= []
map f (a:as) = f a : map f as
-- vordefiniert
Beobachtungen über map
Typ von map
map hat zwei Argumente.
c -> d -> e
Das Ergebnis ist eine Liste.
c -> d -> [b]
Das zweite Argument ist eine Liste.
c -> [a] -> [b]
Das erste Argument ist eine Funktion,
(f -> g) -> [a] -> [b]
die Argumente vom Typ a erhält,
(a -> g) -> [a] -> [b]
und Elemente der Ergebnisliste vom Typ b liefert.
(a -> b) -> [a] -> [b]
map :: (a -> b) -> [a] -> [b]
Programmieren in Haskell
12
Spezialisierungen
map :: (a -> b) -> [a] -> [b]
Spezialisierung von
Anwendung von map
a
b
map c’ [1/4, 1/8, 1/8, 1/4]
Dauer
Musik
Musik
Musik
map genCode cs
Codon
AminoAcid
map (map translate) orfs
zwei Auftreten verschiedenen Typs!
map (transponiere 5)
[cDurTonika, cDurSkala, bruderJakob]
inneres Auftreten
Codon
Protein
äußeres Auftreten
[[Codon]]
[Protein]
Programmieren in Haskell
13
Typklassen und Typkontexte
• Eq enthält alle Typen, deren Elemente man auf Gleichheit testen kann, und
definiert die folgenden Funktionen:
(==) :: (Eq a) => a -> a -> Bool
(/=) :: (Eq a) => a -> a -> Bool
• Ord enthält alle Typen, deren Elemente man bezüglich einer Ordnungsrelation
vergleichen kann, und definiert u.a. die folgenden Funktionen:
(<), (<=), (>=), (>) :: (Ord a) => a -> a -> Bool
max, min
:: (Ord a) => a -> a -> a
Programmieren in Haskell
14
• Num enthält alle numerischen Typen und definiert die grundlegenden
arithmetischen Operationen.
(+), (-), (*) :: (Num a) => a -> a -> a
negate
:: (Num a) => a -> a
Die Funktion negate entspricht dem unären Minus.
• Integral enthält die ganzzahligen Typen Int und Integer und definiert
u.a. die folgenden Funktionen:
div, mod :: (Integral a) => a -> a -> a
even, odd :: (Integral a) => a -> Bool
• Show enthält alle Typen, die eine externe Darstellung als Zeichenketten haben.
Die Funktion show liefert diese Darstellung.
show :: (Show a) => a -> String
Programmieren in Haskell
15
minimum1 :: [Integer] -> Integer
minimum1 [a]
= a
minimum1 (a:as) = min a (minimum1 as)
minimum :: (Ord a) => [a] -> a
minimum [a]
= a
minimum (a:as) = min a (minimum as)
-- vordefiniert
min a b = if a < b then a else b
Programmieren in Haskell
16
Wertdefinitionen, Variablenbindungen
theFinalAnswer :: Integer
theFinalAnswer = 42
aShortList :: [Integer]
aShortList = [1,2,3]
helloWorld :: String
helloWorld = "Hello World"
Programmieren in Haskell
17
theFinalAnswer’ :: Integer
theFinalAnswer’ = 6*7
aShortList’
aShortList’
helloWorld’
helloWorld’
:: [Integer]
= reverse ([3]++[2,1])
:: String
= "Hello" ++ " " ++ "World"
monotonie :: Musik
monotonie = c’ (1/1) :*: monotonie
Programmieren in Haskell
18
Musterbindungen
Tempo t (Instr i (m1 :+: m2 :+: m3:+: m4)) = bruderJakob
Allgemein: p = e, mit p Muster, e Ausdruck
Programmieren in Haskell
19
Funktionsbindungen
length :: [a] -> Int
length []
= 0
length (a:as) = 1 + length as
Programmieren in Haskell
-- vordefiniert
20
Allgemeiner Fall
f p11 . . . p1n
=
e1
...
=
...
f pk1 . . . pkn
=
ek
pij : Muster, ei : Ausdrücke
Programmieren in Haskell
21
Bewachte Gleichungen
dropSpaces :: String -> String
dropSpaces []
= []
dropSpaces (c:cs)
| isSpace c
= dropSpaces cs
| otherwise
= c : dropSpaces cs
squeeze :: String -> String
squeeze []
= []
squeeze (c:c’:cs)
| isSpace c && isSpace c’ = squeeze (c’:cs)
squeeze (c:cs)
= c : squeeze cs
Programmieren in Haskell
22
member :: (Ord a)
member a []
=
member a (b:bs)
| a < b
=
| a == b
=
| a > b
=
Programmieren in Haskell
=> a -> OrdList a -> Bool
False
False
True
member a bs
23
Gleichungen mit lokalen Definitionen
power :: (Num a, Integral b) => a -> b -> a
power x n
| n == 0
= 1
| n ‘mod‘ 2 == 0 = y
| otherwise
= y*x
where y = power (x*x) (n ‘div‘ 2)
Programmieren in Haskell
24
Gleichungen mit lokalen Definitionen
power :: (Num a, Integral b) => a -> b -> a
power x n
| n == 0
= 1
| n ‘mod‘ 2 == 0 = y
| otherwise
= y*x
where y = power (x*x) (n ‘div‘ 2)
pow :: (Num a) => a -> Integer -> a
pow x n
| n == 0
= 1
| otherwise = x * pow x (n-1)
Programmieren in Haskell
24
Gleichungen mit lokalen Definitionen
power :: (Num a, Integral b) => a -> b -> a
power x n
| n == 0
= 1
| n ‘mod‘ 2 == 0 = y
| otherwise
= y*x
where y = power (x*x) (n ‘div‘ 2)
pow :: (Num a) => a -> Integer -> a
pow x n
| n == 0
= 1
| otherwise = x * pow x (n-1)
xn = x2(n div 2)+n mod 2 = (x2 )n div 2 xn mod 2
Programmieren in Haskell
24
Lokale Musterbindung
splitWord :: String -> (String, String)
splitWord []
= ([],[])
splitWord (c:cs)
| isSpace c = ([], c:cs)
| otherwise = (c:w, cs’)
where (w,cs’) = splitWord cs
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
Die allgemeine Form von Gleichungen
f
p11 . . . p1n
m1
pk1 . . . pkn
mk
...
f
Die pij 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
28
Das Rechnen mit Gleichungen
q :: (Num a) => a -> a
q x = 3*x^2 + 1
q 2 - 10
(Definition von q)
⇒
(3 * 2^2 + 1) - 10
⇒
(3 * 4 + 1) - 10
(Definition von (^))
⇒
(12 + 1) - 10
(Definition von (*))
⇒
13 - 10
(Definition von (+))
⇒
3
(Definition von (-))
Paßt f p1 . . . pn | g = e auf Anwendung f a1 . . . an ?
Programmieren in Haskell
29
Vollständige und disjunkte Muster
unique []
= []
unique [a]
= [a]
unique (a:(b:z)) = if a == b then unique (b:z)
else a : unique (b:z)
head :: [a] -> a
-- vordefiniert
head []
= error "head of empty list"
head (a:x) = a
Programmieren in Haskell
30
head’ :: [Integer] -> Maybe Integer
head’ []
= Nothing
head’ (a:x) = Just a
head :: [a] -> a
-- vordefiniert
head’’’ :: [a] -> Maybe a
head’’’ []
= Nothing
head’’’ (a:x) = Just a
Programmieren in Haskell
31
words :: String -> [String]
words xs = wds [] xs
ws :: String ->
wds "" ""
wds ws ""
wds "" (’ ’:xs)
wds "" ( x :xs)
wds ws (’ ’:xs)
wds ws ( x :xs)
Programmieren in Haskell
String -> [String]
= []
= [reverse ws]
= wds "" xs
= wds [x] xs
= (reverse ws) : wds "" xs
= wds (x:ws) xs
32
Bindungsstärken und Assoziativitäten
Bindungsstärke
9
8
7
6
5
4
4
3
2
1
0
Programmieren in Haskell
linksassoziativ
!!
nicht
assoziativ
rechtsassoziativ
.
^, ^^, **
\\
==, /=, <,
<=, >, >=,
‘elem‘,
‘notElem‘
:, ++
*, /,
‘div‘, ‘mod‘,
‘rem‘, ‘quot‘
+, -
&&
||
>>, >>=
$, ‘seq‘
33
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
34
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
35
words :: String -> [String]
-- vordefiniert
words cs = case dropSpaces cs of
[] -> []
cs’ -> w : words cs’’
where (w,cs’’) = splitWord cs’
minimum0’ :: (Ord a) => [a] -> Maybe
minimum0’ []
= Nothing
minimum0’ (a:as) = case minimum0’ as
Nothing -> Just
Just m -> Just
Programmieren in Haskell
a
of
a
(min a m)
36
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
37
Gestaffelte Funktionen
add :: Integer -> Integer -> Integer
add m n = m + n
add’ :: Integer -> (Integer -> Integer)
add’ = \m -> \n -> m + n
Programmieren in Haskell
38
Gestaffelte Funktionen
add :: Integer -> Integer -> Integer
add m n = m + n
add’ :: Integer -> (Integer -> Integer)
add’ = \m -> \n -> m + n
add0 :: (Integer,Integer) -> Integer
add0 (m,n) = m + n
dup :: a -> (a,a)
dup a = (a,a)
double :: Integer -> Integer
double n = add0 (dup n)
Programmieren in Haskell
38
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
39
Lokale Definitionen mit let
power’ :: (Integral b, Num a) => a -> b -> a
power’ x n = if n == 0 then 1
else let y = power’ (x*x) (n ‘div‘ 2)
in if n ‘mod‘ 2 == 0 then y
else y*x
Allgemein:
let {e1 ; . . . ; en } in e .
Programmieren in Haskell
40
Binärbäume
3
1
1
2
2
Programmieren in Haskell
3
4
41
Binärbäume
3
1
1
2
2
data Tree a = Nil
| Leaf a
| Br (Tree a) (Tree a)
Programmieren in Haskell
3
4
deriving Show
41
3
1
t1, t2 :: Tree Integer
2
t1 = Br (Br (Leaf 1) (Leaf 2)) (Leaf 3)
1
t2 = Br (Br (Leaf 1) Nil)
(Br (Br (Leaf 2) (Leaf 3))
(Br Nil (Leaf 4)))
2
Programmieren in Haskell
3
4
42
leaves
leaves
leaves
leaves
:: Tree a -> [a]
Nil
= []
(Leaf a) = [a]
(Br l r) = leaves l ++ leaves r
leftist :: [a] -> Tree a
leftist []
= Nil
leftist (a:as) = Br (leftist as) (Leaf a)
Programmieren in Haskell
43
leaves’
leaves’
leaves’
leaves’
leaves’
:: Tree a -> [a]
Nil
=
(Leaf a)
=
(Br Nil r)
=
(Br (Leaf a) r) =
Programmieren in Haskell
[]
[a]
leaves’ r
a : leaves’ r
44
leaves’
leaves’
leaves’
leaves’
leaves’
:: Tree a -> [a]
Nil
=
(Leaf a)
=
(Br Nil r)
=
(Br (Leaf a) r) =
[]
[a]
leaves’ r
a : leaves’ r
leaves’ (Br (Br l’ r’) r) = leaves’ (Br l’ (Br r’ r))
v
t
Programmieren in Haskell
u
=⇒
t
u
v
44
leaves’
leaves’
leaves’
leaves’
leaves’
leaves’
:: Tree a -> [a]
Nil
(Leaf a)
(Br Nil r)
(Br (Leaf a) r)
(Br (Br l’ r’) r)
=
=
=
=
=
[]
[a]
leaves’ r
a : leaves’ r
leaves’ (Br l’ (Br r’ r))
leaves’ (Br (Br (Leaf 1) (Leaf 2)) (Leaf 3))
⇒
leaves’ (Br (Leaf 1) (Br (Leaf 2) (Leaf 3)))
(Def. leaves’.5)
⇒
1 : leaves’ (Br (Leaf 2) (Leaf 3))
(Def. leaves’.4)
⇒
1 : 2 : leaves’ (Leaf 3)
(Def. leaves’.4)
⇒
1 : 2 : [3]
(Def. leaves’.2)
Programmieren in Haskell
45
build :: [a] -> Tree a
build [] = Nil
build [a] = Leaf a
build as = Br (build (take k as)) (build (drop k as))
where k = length as ‘div‘ 2
take :: Int -> [a] -> [a]
take n (a:as) | n > 0 = a:take (n-1) as
take _ _
= []
Programmieren in Haskell
46
build [1..11]:
1
2
3
6
4
5
9
7
8
10
11
11
=
5+6
=
(2 + 3) + (3 + 3)
=
((1 + 1) + (1 + 2)) + ((1 + 2) + (1 + 2))
=
((1 + 1) + (1 + (1 + 1))) + ((1 + (1 + 1)) + (1 + (1 + 1))) .
Programmieren in Haskell
47
build’ :: [a] -> Tree a
build’ as = fst (buildSplit (length as) as)
buildSplit :: Int -> [a] -> (Tree a, [a])
buildSplit 0 as = (Nil, as)
buildSplit 1 as = (Leaf (head as), tail as)
buildSplit n as = (Br l r, as’’)
where k
= n ‘div‘ 2
(l,as’) = buildSplit
k as
(r,as’’) = buildSplit (n-k) as’
Programmieren in Haskell
48
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
49
• 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
50
Auswertung von Fallunterscheidungen
case C e1 ...ek of {...; C x1 ...xk -> e;...}
(case-Regel)
⇒ e[x1 /e1 , . . . , xn /en ]
Programmieren in Haskell
51
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)
52
Auswertung von Funktionsanwendungen
(\x -> e) a ⇒ e[x/a]
Programmieren in Haskell
(β-Regel)
(1)
53
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)
54
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
55
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)
56
Herunterladen