Haskell Syntax - Universität Bielefeld

Werbung
Programmieren in
Haskell
Stefan
Janssen
Programmieren in Haskell
Haskell Syntax
Stefan Janssen
Universität Bielefeld
AG Praktische Informatik
October 12, 2014
Haskell Syntax
Scopes
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Wir beginnen mit einem Überblick über die Syntax von Haskell
Namen versus Schlüsselwörter
Programmieren in
Haskell
Stefan
Janssen
Namen bezeichnen Werte (aller Art) und sind frei wählbar
Schlüsselwörter strukturieren das Programm; sie dürfen nicht
als Namen verwendet werden
Namen und Schlüsselwörter dürfen nicht durch Leerzeichen
oder Zeilenende unterbrochen werden
Nicht zu verwechseln: Schlüsselwörter und vordefinierte Namen
Haskell Syntax
Scopes
Schlüsselwörter
1
2
3
case class data default deriving do else
if import in infix infixl infixr instance
let module newtype of then type where _
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Schlüsselwörter
1
2
3
case class data default deriving do else
if import in infix infixl infixr instance
let module newtype of then type where _
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Vergleich
Scopes
Sprache
#Keywords
Haskell
Scheme
C (C89)
Java
Ada
C++
21
23
32
50
72
74
Groß- und Kleinschreibung in Namen
Programmieren in
Haskell
Modulname
erster Buchstabe großgeschrieben
Modulname == Dateiname
Stefan
Janssen
Haskell Syntax
Scopes
Datentypnamen: Großgeschrieben
Datentyp-Konstrukturen: Großgeschrieben
(z.B. Datentyp Bool → Konstruktoren: True und False)
Variablen, Funktionsnamen: Kleingeschrieben
Operatorzeichen → Infix-Schreibweise
Sonstige Funktionsnamen: Präfix-Schreibweise
Prioritäten und Assoziation sind definierbar
Keine (!) Anweisungen
Programmieren in
Haskell
Für Kenner von Java, C, Pascal, ...:
keine Statements in Haskell
keine Wertzuweisung, kein FOR, kein WHILE ...
Stefan
Janssen
Haskell Syntax
Scopes
Keine (!) Anweisungen
Programmieren in
Haskell
Für Kenner von Java, C, Pascal, ...:
keine Statements in Haskell
keine Wertzuweisung, kein FOR, kein WHILE ...
→ da funktionale Programmiersprache
Es wird beschrieben, WAS berechnet werden soll, aber nicht
WIE. So wie in
(1 + f (2)) ∗ 32 ∗ (4 + g(5))
Hier ist nicht festgelegt, ob zuerst f (2), 32 , oder g(5)
berechnet wird
Stefan
Janssen
Haskell Syntax
Scopes
Funktionsdefinitionen
1
2
3
4
Einfache Funktionsgleichungen:
> p x
= 5* x ^2 -7* x +9
> aba x y
= x ++ y ++ x
> f n
= if n ==0 then 1 else n * f (n -1)
> g x y z
= f (x * p y ) - z
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
5
6
7
8
9
10
> dnacomp b = if b == ’A ’ then ’T ’ else
>
if b == ’C ’ then ’G ’ else
>
if b == ’G ’ then ’C ’ else
>
if b == ’T ’ then ’A ’ else
>
error " illegal symbol in DNA "
Allgemein:
f p1 ... pk = Ausdruck, der p1 bis pk enthält
Mustergleichungen (pattern matching)
Programmieren in
Haskell
1
2
Mustergleichungen treffen Fallunterscheidungen auf der linken
Seite (und erlauben mehr als eine Gleichung)
> ff 0 = 1
> ff n = n * f (n -1) -- ueberlappende Muster
Stefan
Janssen
Haskell Syntax
Scopes
3
4
5
6
7
8
>
>
>
>
>
dnaComp
dnaComp
dnaComp
dnaComp
dnaComp
’A ’
’C ’
’G ’
’T ’
_
=
=
=
=
=
’T ’
’G ’
’C ’
’A ’
error " illegal symbol in DNA "
_ bezeichnet ein Argument, das nicht gebraucht wird
Fehlerbehandlung
Es gibt mehrere Möglichkeiten, Fehler zu behandeln in Haskell
Programmen (mindestens 8)
einfachster Mechanismus ist die Funktion error
Programmieren in
Haskell
Stefan
Janssen
error msg darf überall in einem Ausdruck stehen
Haskell Syntax
msg ist ein String
Scopes
error msg führt zum Programmabbruch mit Ausgabe von
msg
Die Funktion hat einen ganz besonderen Typ:
error :: String -> a
Fehlerbehandlung
Es gibt mehrere Möglichkeiten, Fehler zu behandeln in Haskell
Programmen (mindestens 8)
einfachster Mechanismus ist die Funktion error
Haskell Syntax
msg ist ein String
Scopes
Die Funktion hat einen ganz besonderen Typ:
error :: String -> a
Example
2
3
Stefan
Janssen
error msg darf überall in einem Ausdruck stehen
error msg führt zum Programmabbruch mit Ausgabe von
msg
1
Programmieren in
Haskell
> divide a b =
>
if b == 0 then error " divide by zero "
>
else div a b
Präfix, Infix, Postfix-Notation
Die Mathematik hat viele Schreibweisen für Ausdrücke
erfunden, um sie gut lesbar zu machen
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Notation
Präfix
Infix
Postfix
Grafix
mathematisch
−1, f (x , y , z)
x < y , n2 , 2x + 5
0
n!,
q f √
3
1− y
Rb
in Haskell
-1, f x y z
x<y, nˆ2, 2*x+5
--root 3 (1 - (root 2 y))
integral a b f
a f (x ) dx
Präfix-Notation ohne Klammern ist der Regelfall in Haskell.
Was ist der Unterschied zwischen f a g b und f a (g b) ?
Operatoren
Zweistellige Funktionen mit Infix-Schreibweise nennt man
Operatoren.
Boolsche Operatoren sind vordefiniert:
|| oder
&& und
‘not‘
Vergleichsoperatoren: < <= == /= . . .
Arithmetik:
+ - * / ‘div‘ ‘mod‘
Zeichenreichen:
: ++
Operatoren sind reguläre Funktionen in Haskell; nur die
Infix-Notation und die gegebenen Prioritäten sind das
Besondere.
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Operatoren
Zweistellige Funktionen mit Infix-Schreibweise nennt man
Operatoren.
Boolsche Operatoren sind vordefiniert:
|| oder
&& und
‘not‘
Vergleichsoperatoren: < <= == /= . . .
Arithmetik:
+ - * / ‘div‘ ‘mod‘
Zeichenreichen:
: ++
Operatoren sind reguläre Funktionen in Haskell; nur die
Infix-Notation und die gegebenen Prioritäten sind das
Besondere.
Example
Main> let (+) x y = x*y in 2+3
6
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Prefix/Infix-Konversion
Funktionen als Operatoren
Operatoren als Funktionen
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Prefix/Infix-Konversion
Funktionen als Operatoren
Operatoren als Funktionen
‘fn‘ konvertiert nach Infix
(op) konvertiert nach Prefix
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Prefix/Infix-Konversion
Funktionen als Operatoren
Operatoren als Funktionen
‘fn‘ konvertiert nach Infix
(op) konvertiert nach Prefix
Example
Main>
23
Main>
23
Test>
23
Test>
23
21 + 2
(+) 21 2
div 69 3
69 ‘div‘ 3
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Prefix/Infix: Prioritäten
Programmieren in
Haskell
Stefan
Janssen
Flexible Anwendung von Funktionen
Haskell Syntax
Deklaration von Prioritäten möglich
meist geeignet vordefiniert – siehe Haskell report
Scopes
Funktionsanwendung in Präfix hat höchste Priorität
1
2
3
f x + g y * 2
ist
( f x ) + (( g y ) *2)
fuer einstelliges f und g
Achtung bei Definitionen :
4
5
f ( x : xs ) ys = x : f xs ys
braucht Klammern !!
Bedingter Ausdruck
1
if expr1 then expr2 else expr3
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Bedingter Ausdruck
1
if expr1 then expr2 else expr3
Programmieren in
Haskell
Stefan
Janssen
Example
Haskell Syntax
1
f a b
= if a <= b then a +1 else b -2
Scopes
Bedingter Ausdruck
1
if expr1 then expr2 else expr3
Programmieren in
Haskell
Stefan
Janssen
Example
Haskell Syntax
1
f a b
= if a <= b then a +1 else b -2
Kein If-Statement!
if expr1 then expr2 ?
Scopes
Bedingter Ausdruck
1
if expr1 then expr2 else expr3
Programmieren in
Haskell
Stefan
Janssen
Example
Haskell Syntax
1
f a b
= if a <= b then a +1 else b -2
Kein If-Statement!
if expr1 then expr2 ?
Fehler!
→ hier wäre der Wert des Ausdrucks im else-Fall nicht
definiert
Scopes
Bedingter Ausdruck
1
if expr1 then expr2 else expr3
Programmieren in
Haskell
Stefan
Janssen
Example
Haskell Syntax
1
f a b
= if a <= b then a +1 else b -2
Kein If-Statement!
if expr1 then expr2 ?
Fehler!
→ hier wäre der Wert des Ausdrucks im else-Fall nicht
definiert
Vergleichbar mit dem Bedingungsoperator in C/Java:
cond_expr ? expr2 : expr3
Scopes
Sichtbarkeitsbereiche
Programmieren in
Haskell
Alle (modernen) Programiersprachen haben
Sichtbarkeitsbereiche (scopes).
Jeder Name ist in dem Bereich sichtbar
in dem er definiert wurde
und in allen darin eingebetteteten Bereichen ...
... es sei denn, er wird verschattet
Scopes in einem Programm sind also “verschachtelt”.
Explizite Regeln gelten für Sichtbarkeit über Modulgrenzen
hinweg.
Stefan
Janssen
Haskell Syntax
Scopes
Layout und Abseitsregel
“Whitespace” sind Zeichen ohne Bedeutung:
Leerzeichen, NeueZeile, Kommentar
Haskell-Programme sind whitespace-sensitive
es gilt die Offside-Rule (Abseitsregel)
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
→ die Einrückung ist entscheidend
Layout und Abseitsregel
“Whitespace” sind Zeichen ohne Bedeutung:
Leerzeichen, NeueZeile, Kommentar
Haskell-Programme sind whitespace-sensitive
es gilt die Offside-Rule (Abseitsregel)
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
→ die Einrückung ist entscheidend
in der Regel Verzicht auf Trennzeichen wie ; {},
aber explizite Verwendung von ; {} ist möglich
Layout und Abseitsregel
“Whitespace” sind Zeichen ohne Bedeutung:
Leerzeichen, NeueZeile, Kommentar
Haskell-Programme sind whitespace-sensitive
es gilt die Offside-Rule (Abseitsregel)
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
→ die Einrückung ist entscheidend
in der Regel Verzicht auf Trennzeichen wie ; {},
aber explizite Verwendung von ; {} ist möglich
Example (richtig vs falsch)
1
2
3
4
> dreh (x , y ) =
> schieb (x , y )=
> heb (x , y )
=
>
( -y , x )
( x +1 , y )
(x ,
y +1)
> dreh (x , y )= ( -y , x )
>
schieb (x , y )=( x +1 , y )
> heb (x , y )= (x ,
> y +1)
Layout definiert Sichtbarkeitsbereiche
Programmieren in
Haskell
Neue Bereiche entstehen nach of, where, let:
Haskell Syntax
Example (richtig)
1
2
3
4
5
6
>
>
>
>
>
>
show xs =
where
show ’
show ’
show ’
Stefan
Janssen
Scopes
" [ " ++ show ’ xs ++ " ] "
Nil
= ""
( Cons x Nil ) = show x
( Cons x xs ) = show x ++ " ,"
++ show ’ xs
Layout
Programmieren in
Haskell
Definitionen gleicher Stufe müssen in der gleichen Einrücktiefe
stehen
Example (falsch)
1
2
3
4
5
6
>
>
>
>
>
>
show xs = " [ " ++ show ’ xs ++ " ] "
where
show ’ Nil
= ""
show ’ ( Cons x Nil ) = show x
show ’ ( Cons x xs ) = show x ++ " ,"
++ show ’ xs
Stefan
Janssen
Haskell Syntax
Scopes
Explizite Scopes
Programmieren in
Haskell
Stefan
Janssen
Gleichwertig sind
Haskell Syntax
Example
1
2
3
4
5
> f x = g x +
>
where { g
> f x = g x +
>
where g x
h x
Scopes
h
x
h
=
=
x
= x * x ; h x = x + x }
x
x * x
x + x
Allgemeine Abseitsregel
Scopes sind Sichtbarkeitsbereiche von (Gruppen von)
Definitionen
alle Definitionen eines Scope stehen in der gleichen
Einrücktiefe
tieferes Einrücken bedeutet Fortsetzung der aktuellen
Definitionszeile
nach let, where, of, do bestimmt der nächste
Buchstabe die neue Einrücktiefe
Ausrücken nach links beendet den aktuellen Scope
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Allgemeine Abseitsregel
Scopes sind Sichtbarkeitsbereiche von (Gruppen von)
Definitionen
alle Definitionen eines Scope stehen in der gleichen
Einrücktiefe
tieferes Einrücken bedeutet Fortsetzung der aktuellen
Definitionszeile
nach let, where, of, do bestimmt der nächste
Buchstabe die neue Einrücktiefe
Ausrücken nach links beendet den aktuellen Scope
Vorteile ??
Nachteile ??
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Noch mehr Syntax
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Die folgenden Syntax-Elemente werden wir erst später
kennelernen, wenn die entsprechenden Sprachkonstrukte
behandelt werden. Sie sind hier nur der Vollständigkeit halber
aufgeführt.
Scopes
Case-Ausdruck (pp.)
vielfache Fallunterscheidung
statt verschachtelte If-Expressions
Programmieren in
Haskell
Stefan
Janssen
überall wo ein Ausdruck stehen kann
Haskell Syntax
Pattern matching
Scopes
Case-Ausdruck (pp.)
vielfache Fallunterscheidung
statt verschachtelte If-Expressions
1
2
3
4
5
Programmieren in
Haskell
Stefan
Janssen
überall wo ein Ausdruck stehen kann
Haskell Syntax
Pattern matching
Scopes
case expr of
pat1 | guard1 -> expr1
pat2 | guard2 -> expr2
pat3 | guard3 -> expr3
...
Case-Ausdruck (pp.)
vielfache Fallunterscheidung
statt verschachtelte If-Expressions
1
2
3
4
5
Programmieren in
Haskell
Stefan
Janssen
überall wo ein Ausdruck stehen kann
Haskell Syntax
Pattern matching
Scopes
case expr of
pat1 | guard1 -> expr1
pat2 | guard2 -> expr2
pat3 | guard3 -> expr3
...
Pattern kann leer sein
statt pat | True -> gilt auch die Konvention pat ->
otherwise als default
Case-Ausdruck
Programmieren in
Haskell
Stefan
Janssen
Example
Haskell Syntax
Scopes
1
2
3
4
5
> laststr xs = case reverse xs of
>
[]
-> " leer "
>
( l : ls ) | l == 1 -> " eins "
>
( l : ls ) | l == 2 -> " zwei "
>
otherwise
-> " ganz viele "
Let Expression
1
2
3
4
let decl1
decl2
...
in expr
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Let Expression
1
2
3
4
let decl1
decl2
...
in expr
Kann überall dort stehen wo ein
Ausdruck stehen kann
lokaler Scope (Sichtbarkeitsbereich)
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Let Expression
let decl1
decl2
...
in expr
1
2
3
4
Kann überall dort stehen wo ein
Ausdruck stehen kann
lokaler Scope (Sichtbarkeitsbereich)
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Example
1
2
3
> func a b
>
>
= let square x = x * x
plus a b = a + b
in plus ( square a ) ( square b )
Let Expression
let decl1
decl2
...
in expr
1
2
3
4
Kann überall dort stehen wo ein
Ausdruck stehen kann
lokaler Scope (Sichtbarkeitsbereich)
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Example
1
2
3
1
2
3
> func a b
>
>
= let square x = x * x
plus a b = a + b
in plus ( square a ) ( square b )
Versus:
> square x = x * x
> plus a b = a + b
> func a b = plus ( square a ) ( square b )
Hier sind plus und square auch außerhalb von func bekannt.
Where-Notation
lokale Definitionen
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Where-Notation
lokale Definitionen
bei Funktionsdefinitionen
case-Ausdrücken
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Where-Notation
lokale Definitionen
bei Funktionsdefinitionen
case-Ausdrücken
Module-Definition . . .
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Where-Notation
lokale Definitionen
bei Funktionsdefinitionen
case-Ausdrücken
Module-Definition . . .
Example
1
2
3
> f x = square x + square x
>
where
>
square x = x * x
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Where-Notation
lokale Definitionen
bei Funktionsdefinitionen
case-Ausdrücken
Module-Definition . . .
Example
1
2
3
> f x = square x + square x
>
where
>
square x = x * x
vs. let Ausdruck
notationelle Betonung
syntaktischer Zucker
where kann nicht überall stehen
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Where-Notation
Programmieren in
Haskell
Stefan
Janssen
1
2
3
4
5
Schachtelungen auch möglich:
> foo x = ... f ...
>
where
>
f x = ... g ...
>
where
>
g x = ....
Haskell Syntax
Scopes
Modul-Aufbau
Modulname
Imports
Definitionen
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Modul-Aufbau
Programmieren in
Haskell
Modulname
Imports
Definitionen
1
2
> module Meinmodul
> where
Stefan
Janssen
Haskell Syntax
Scopes
3
4
> import Data . List
5
6
> splits n = [ splitAt k [1.. n ] | k < -[1.. n -1]]
Modul-Aufbau
Programmieren in
Haskell
Modulname
Imports
Definitionen
1
2
Stefan
Janssen
Haskell Syntax
> module Meinmodul
> where
Scopes
3
4
> import Data . List
5
6
> splits n = [ splitAt k [1.. n ] | k < -[1.. n -1]]
Main> splits
[ ( [1
( [1,2
( [1,2,3
( [1,2,3,4
5
],[
],[
],[
],[
2,3,4,5]
3,4,5]
4,5]
5]
)
)
)
)
,
,
,
]
Wächter (Guards) in Funktionsdefinitionen (pp.)
1
2
3
4
> fn pat1 pat2 ...
>
| guard1 = expr1
>
| guard2 = expr2
>
...
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Wächter (Guards) in Funktionsdefinitionen (pp.)
1
2
3
4
> fn pat1 pat2 ...
>
| guard1 = expr1
>
| guard2 = expr2
>
...
syntaktische Zucker für Funktionsdefinitionen
ersetzt geschachtelte if-Anweisungen
guards (Wächter) sind Ausdrücke (vom Typ Bool)
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Wächter (Guards) in Funktionsdefinitionen (pp.)
1
2
3
4
> fn pat1 pat2 ...
>
| guard1 = expr1
>
| guard2 = expr2
>
...
syntaktische Zucker für Funktionsdefinitionen
ersetzt geschachtelte if-Anweisungen
guards (Wächter) sind Ausdrücke (vom Typ Bool)
Example
1
2
3
4
howManyEqual n m p
| ( n == m ) && ( m == p )
= 3
| ( n == m ) || ( m == p ) || ( n == p ) = 2
| otherwise
= 0
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Pattern matching
Pattern Matching auf
natürlichen Zahlen
Werten
Datentyp-Konstruktoren
Joker _
auf der linken Seite von Funktionsdefinitionen
in case-Ausdrücken
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Pattern matching
Pattern Matching auf
natürlichen Zahlen
Werten
Datentyp-Konstruktoren
Joker _
auf der linken Seite von Funktionsdefinitionen
in case-Ausdrücken
Example
1
2
3
> take ’
:: Int -> [ a ] -> [ a ]
> take ’ ( n +1) ( a : as ) = a : take ’ n as
> take ’ _
_
= []
Programmieren in
Haskell
Stefan
Janssen
Haskell Syntax
Scopes
Pattern matching
In der Anwendung wird die erste Gleichung benutzt, deren
Muster auf die Argumente passen.
Example
1
2
3
4
>
>
>
>
f
f
f
f
( a : b : c : d : ds )
( a : as )
( a :[])
[a]
7
8
> g 0
> g 1
> g _
Stefan
Janssen
Haskell Syntax
=
=
=
=
...
...
...
...
5
6
Programmieren in
Haskell
= ...
= ...
= ...
Wo es geht, wählt man die Muster einander ausschließend.
Scopes
Herunterladen