1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
|
---
language: Elm
filename: learnelm.elm
contributors:
- ["Max Goldstein", "http://maxgoldste.in/"]
translators:
- ["waynee95", "https://waynee95.me"]
lang: de-de
---
Elm ist eine pure funktionale Programmiersprache. Mit Elm werden GUIs
(grafische Benutzeroberfläche) für Webanwendungen erstellt. Durch die statische
Typisierung kann Elm viele Fehler schon bei der Kompilierung abfangen. Ein
Hauptmerkmal von Elm sind die ausführlichen und gut erklärten Fehlermeldungen.
```haskell
-- Einzeilige Kommentare beginnen mit 2 Bindestrichen.
{- So wird ein mehrzeiliger Kommentar angelegt.
{- Diese können auch verschachtelt werden. -}
-}
{-- Die Grundlagen --}
-- Arithmetik
1 + 1 -- 2
8 - 1 -- 7
10 * 2 -- 20
-- Zahlen ohne Punkt sind entweder vom Typ Int oder Float.
33 / 2 -- 16.5 mit Division von Gleitkommazahlen
33 // 2 -- 16 mit ganzzahliger Division
-- Exponenten
5 ^ 2 -- 25
-- Boolsche Werte
not True -- False
not False -- True
1 == 1 -- True
1 /= 1 -- False
1 < 10 -- True
-- Strings (Zeichenketten) und Zeichen
"Das hier ist ein String."
'a' -- Zeichen
-- Strings können konkateniert werden.
"Hello " ++ "world!" -- "Hello world!"
{-- Listen und Tupel --}
-- Jedes Element einer Liste muss vom gleichen Typ sein. Listen sind homogen.
["the", "quick", "brown", "fox"]
[1, 2, 3, 4, 5]
-- Das zweite Beispiel kann man auch mit Hilfe der "range" Funktion schreiben.
List.range 1 5
-- Listen werden genauso wie Strings konkateniert.
List.range 1 5 ++ List.range 6 10 == List.range 1 10 -- True
-- Mit dem "cons" Operator lässt sich ein Element an den Anfang einer Liste anfügen.
0 :: List.range 1 5 -- [0, 1, 2, 3, 4, 5]
-- Die Funktionen "head" und "tail" haben als Rückgabewert den "Maybe" Typ.
-- Dadurch wird die Fehlerbehandlung von fehlenden Elementen explizit, weil
-- man immer mit jedem möglichen Fall umgehen muss.
List.head (List.range 1 5) -- Just 1
List.tail (List.range 1 5) -- Just [2, 3, 4, 5]
List.head [] -- Nothing
-- List.funktionsName bedeutet, dass diese Funktion aus dem "List"-Modul stammt.
-- Tupel sind heterogen, jedes Element kann von einem anderen Typ sein.
-- Jedoch haben Tupel eine feste Länge.
("elm", 42)
-- Das Zugreifen auf Elemente eines Tupels geschieht mittels den Funktionen
-- "first" und "second".
Tuple.first ("elm", 42) -- "elm"
Tuple.second ("elm", 42) -- 42
-- Das leere Tupel, genannt "Unit", wird manchmal als Platzhalter verwendet.
-- Es ist das einzige Element vom Typ "Unit".
()
{-- Kontrollfluss --}
-- Eine If-Bedingung hat immer einen Else-Zweig und beide Zweige müssen den
-- gleichen Typ haben.
if powerLevel > 9000 then
"WHOA!"
else
"meh"
-- If-Bedingungen können verkettet werden.
if n < 0 then
"n is negative"
else if n > 0 then
"n is positive"
else
"n is zero"
-- Mit dem Mustervergleich (pattern matching) kann man bestimmte Fälle direkt
-- behandeln.
case aList of
[] -> "matches the empty list"
[x]-> "matches a list of exactly one item, " ++ toString x
x::xs -> "matches a list of at least one item whose head is " ++ toString x
-- Mustervergleich geht immer von oben nach unten. Würde man [x] als letztes
-- platzieren, dann würde dieser Fall niemals getroffen werden, weil x:xs diesen
-- Fall schon mit einschließt (xs ist in dem Fall die leere Liste).
-- Mustervergleich an einem Maybe Typ.
case List.head aList of
Just x -> "The head is " ++ toString x
Nothing -> "The list was empty."
{-- Funktionen --}
-- Die Syntax für Funktionen in Elm ist minimal. Hier werden Leerzeichen anstelle
-- von runden oder geschweiften Klammern verwendet. Außerdem gibt es kein "return"
-- Keyword.
-- Eine Funktion wird durch ihren Namen, einer Liste von Parametern gefolgt von
-- einem Gleichheitszeichen und dem Funktionskörper angegeben.
multiply a b =
a * b
-- Beim Aufruf der Funktion (auch Applikation genannt) werden die Argumente ohne
-- Komma übergeben.
multiply 7 6 -- 42
-- Partielle Applikation einer Funktion (Aufrufen einer Funktion mit fehlenden
-- Argumenten). Hierbei entsteht eine neue Funktion, der wir einen Namen geben.
double =
multiply 2
-- Konstanten sind Funktionen ohne Parameter.
answer =
42
-- Funktionen, die Funktionen als Parameter haben, nennt man Funktionen höherer
-- Ordnung. In funktionalen Programmiersprachen werden Funktionen als "first-class"
-- behandelt. Man kann sie als Argument übergeben, als Rückgabewert einer Funktion
-- zurückgeben oder einer Variable zuweisen.
List.map double (List.range 1 4) -- [2, 4, 6, 8]
-- Funktionen können auch als anonyme Funktion (Lambda-Funktionen) übergeben werden.
-- Diese werden mit einem Blackslash eingeleitet, gefolgt von allen Argumenten.
-- Die Funktion "\a -> a * 2" beschreibt die Funktion f(x) = x * 2.
List.map (\a -> a * 2) (List.range 1 4) -- [2, 4, 6, 8]
-- Mustervergleich kann auch in der Funktionsdefinition verwendet werden.
-- In diesem Fall hat die Funktion ein Tupel als Parameter. (Beachte: Hier
-- werden die Werte des Tupels direkt ausgepackt. Dadurch kann man auf die
-- Verwendung von "first" und "second" verzichten.)
area (width, height) =
width * height
area (6, 7) -- 42
-- Mustervergleich auf Records macht man mit geschweiften Klammern.
-- Bezeichner (lokale Variablen) werden mittels dem "let" Keyword angelegt.
-- (Mehr zu Records weiter unten!)
volume {width, height, depth} =
let
area = width * height
in
area * depth
volume { width = 3, height = 2, depth = 7 } -- 42
-- Rekursive Funktion
fib n =
if n < 2 then
1
else
fib (n - 1) + fib (n - 2)
List.map fib (List.range 0 8) -- [1, 1, 2, 3, 5, 8, 13, 21, 34]
-- Noch eine rekursive Funktion (Nur ein Beispiel, verwende stattdessen immer
-- List.length!)
listLength aList =
case aList of
[] -> 0
x::xs -> 1 + listLength xs
-- Funktionsapplikation hat die höchste Präzedenz, sie binden stärker als Operatoren.
-- Klammern bietet die Möglichkeit der Bevorrangung.
cos (degrees 30) ^ 2 + sin (degrees 30) ^ 2 -- 1
-- Als erstes wird die Funktion "degrees" mit dem Wert 30 aufgerufen.
-- Danach wird das Ergenis davon den Funktionen "cos", bzw. "sin" übergeben.
-- Dann wird das Ergebnis davon mit 2 quadriert und als letztes werden diese
-- beiden Werte dann addiert.
{-- Typen und Typ Annotationen --}
-- Durch Typinferenz kann der Compiler jeden Typ genau bestimmen. Man kann diese
-- aber auch manuell selber angeben (guter Stil!).
-- Typen beginnen immer mit eine Großbuchstaben. Dabei liest man "x : Typ" als
-- "x" ist vom Typ "Typ".
-- Hier ein paar übliche Typen:
5 : Int
6.7 : Float
"hello" : String
True : Bool
-- Funktionen haben ebenfalls einen Typ. Dabei ist der ganz rechte Typ der
-- Rückgabetyp der Funktion und alle anderen sind die Typen der Parameter.
not : Bool -> Bool
round : Float -> Int
-- Es ist guter Stil immer den Typ anzugeben, da diese eine Form von Dokumentation
-- sind. Außerdem kann so der Compiler genauere Fehlermeldungen geben.
double : Int -> Int
double x = x * 2
-- Funktionen als Parameter werden durch Klammern angegeben. Die folgende Funktion
-- ist nicht auf einen Typ festgelegt, sondern enthält Typvariablen (beginnend
-- mit Kleinbuchstaben). Die konkreten Typen werden erst bei Anwendung der
-- Funktion festgelegt. "List a" bedeutet, dass es sich um eine Liste mit
-- Elementen vom Typ "a" handelt.
List.map : (a -> b) -> List a -> List b
-- Es gibt drei spezielle kleingeschriebene Typen: "number", "comparable" und
-- "appendable".
add : number -> number -> number
add x y = x + y -- funktioniert mit Ints und Floats.
max :: comparable -> comparable -> comparable
max a b = if a > b then a else b -- funktioniert mit Typen, die vergleichbar sind.
append :: appendable -> appendable -> appendable
append xs ys = xs ++ ys -- funktioniert mit Typen, die konkatenierbar sind.
append "hello" "world" -- "helloworld"
append [1,1,2] [3,5,8] -- [1,1,2,3,5,8]
{-- Eigene Datentypen erstellen --}
-- Ein "Record" ist ähnlich wie ein Tupel, nur das jedes Feld einen Namne hat.
-- Dabei spielt die Reihenfolge keine Rolle.
{ x = 3, y = 7 }
-- Um auf Werte eines Records zuzugreifen, benutzt man einen Punkt gefolgt
-- von dem Namen des Feldes.
{ x = 3, y = 7 }.x -- 3
-- Oder mit einer Zugriffsfunktion, welche aus einem Punkt und dem Feldnamen besteht.
.y { x = 3, y = 7 } -- 7
-- Wert eines Feldes ändern. (Achtung: Das Feld muss aber vorher schon vorhanden sein!)
{ person |
name = "George" }
-- Mehrere Felder aufeinmal ändern unter Verwendung des alten Wertes.
{ particle |
position = particle.position + particle.velocity,
velocity = particle.velocity + particle.acceleration }
-- Du kannst ein Record auch als Typ Annotation verwenden.
-- (Beachte: Ein Record Typ benutzt einen Doppelpunkt und ein Record Wert benutzt
-- ein Gleichheitszeichen!)
origin : { x : Float, y : Float, z : Float }
origin =
{ x = 0, y = 0, z = 0 }
-- Durch das "type" Keyword kann man einem existierenden Typen einen Namen geben.
type alias Point3D =
{ x : Float, y : Float, z : Float }
-- Der Name kann dann als Konstruktor verwendet werden.
otherOrigin : Point3D
otherOrigin =
Point3D 0 0 0
-- Aber es ist immernoch der selbe Typ, da es nur ein Alias ist!
origin == otherOrigin -- True
-- Neben den Records gibt es auch noch so genannte Summentypen.
-- Ein Summentyp hat mehrere Konstruktoren.
type Direction =
North | South | East | West
-- Ein Konstruktor kann außerdem noch andere Typen enthalten. Rekursion ist
-- auch möglich.
type IntTree =
Leaf | Node Int IntTree IntTree
-- Diese können auch als Typ Annotation verwendet werden.
root : IntTree
root =
Node 7 Leaf Leaf
-- Außerdem können auch Typvariablen verwendet werden in einem Konstruktor.
type Tree a =
Leaf | Node a (Tree a) (Tree a)
-- Beim Mustervergleich kann man auf die verschiedenen Konstruktoren matchen.
leftmostElement : Tree a -> Maybe a
leftmostElement tree =
case tree of
Leaf -> Nothing
Node x Leaf _ -> Just x
Node _ subtree _ -> leftmostElement subtree
{-- Module und Imports --}
-- Die Kernbibliotheken und andere Bibliotheken sind in Module aufgeteilt.
-- Für große Projekte können auch eigene Module erstellt werden.
-- Eine Modul beginnt mit ganz oben. Ohne diese Angabe befindet man sich
-- automatisch im Modul "Main".
module Name where
-- Ohne genaue Angabe von Exports wird alles exportiert. Es können aber alle
-- Exporte explizit angegeben werden.
module Name (MyType, myValue) where
-- Importiert das Modul "Dict". Jetzt kann man Funktionen mittels "Dict.insert"
-- aufrufen.
import Dict
-- Importiert das "Dict" Modul und den "Dict" Typ. Dadurch muss man nicht "Dict.Dict"
-- verwenden. Man kann trotzdem noch Funktionen des Moduls aufrufen, wie "Dict.insert".
import Dict exposing (Dict)
-- Abkürzung für den Modulnamen. Aufrufen der Funktionen mittels "C.funktionsName".
import Graphics.Collage as C
{-- Kommandozeilen Programme --}
-- Eine Elm-Datei kompilieren.
$ elm make MyFile.elm
-- Beim ersten Aufruf wird Elm die "core" Bibliotheken installieren und eine
-- "elm-package.json"-Datei anlegen, die alle Informationen des Projektes
-- speichert.
-- Der Reactor ist ein Server, welche alle Dateinen kompiliert und ausführt.
$ elm reactor
-- Starte das REPL (read-eval-print-loop).
$ elm repl
-- Bibliotheken werden durch den Github-Nutzernamen und ein Repository identifiziert.
-- Installieren einer neuen Bibliothek.
$ elm package install elm-lang/html
-- Diese wird der elm-package.json Datei hinzugefügt.
-- Zeigt alle Veränderungen zwischen zwei bestimmten Versionen an.
$ elm package diff elm-lang/html 1.1.0 2.0.0
-- Der Paketmanager von Elm erzwingt "semantic versioning"!
```
Elm ist eine besonders kleine Programmiersprache. Jetzt hast du genug Wissen an
deiner Seite, um dich in fast jedem Elm Code zurecht zu finden.
Noch ein paar weitere hilfreiche Ressourcen (in Englisch):
- Die [Elm Homepage](http://elm-lang.org/). Dort findest du:
- [Anleitung zur Installierung von Elm](http://elm-lang.org/install)
- [Dokumentation](http://elm-lang.org/docs), sowie eine [Referenz zur Syntax](http://elm-lang.org/docs/syntax)
- Viele hilfreiche [Beispiele](http://elm-lang.org/examples)
- Dokumentation der [Elm Kernbibliotheken](http://package.elm-lang.org/packages/elm-lang/core/latest/). Insbesondere:
- [Basics](http://package.elm-lang.org/packages/elm-lang/core/latest/Basics) (standardmäßig importiert)
- [Maybe](http://package.elm-lang.org/packages/elm-lang/core/latest/Maybe) sowie [Result](http://package.elm-lang.org/packages/elm-lang/core/latest/Result) (benutzt für Fehlerbehandlung)
- Datenstrukturen, wie [List](http://package.elm-lang.org/packages/elm-lang/core/latest/List), [Array](http://package.elm-lang.org/packages/elm-lang/core/latest/Array), [Dict](http://package.elm-lang.org/packages/elm-lang/core/latest/Dict), und [Set](http://package.elm-lang.org/packages/elm-lang/core/latest/Set)
- JSON [encoding](http://package.elm-lang.org/packages/elm-lang/core/latest/Json-Encode) und [decoding](http://package.elm-lang.org/packages/elm-lang/core/latest/Json-Decode)
- [Die Elm Architektur](https://github.com/evancz/elm-architecture-tutorial#the-elm-architecture).
- Die [Elm mailing list](https://groups.google.com/forum/#!forum/elm-discuss).
|