From 3e22775a641831a82c59a3b6197240b2fcd9a76b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Juc=C3=A1?= Date: Thu, 27 Apr 2023 17:09:38 -0300 Subject: Fix bad case in the Elixir language --- de-de/elixir-de.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'de-de/elixir-de.html.markdown') diff --git a/de-de/elixir-de.html.markdown b/de-de/elixir-de.html.markdown index 254cca51..ec933696 100644 --- a/de-de/elixir-de.html.markdown +++ b/de-de/elixir-de.html.markdown @@ -1,5 +1,5 @@ --- -language: elixir +language: Elixir contributors: - ["Joao Marques", "http://github.com/mrshankly"] translators: -- cgit v1.2.3 From 818b8eec46b11b36b5235ecbce540557afec4687 Mon Sep 17 00:00:00 2001 From: Boris Verkhovskiy Date: Thu, 4 Apr 2024 00:27:01 -0700 Subject: Convert \r\n to \n --- de-de/elixir-de.html.markdown | 846 +++++++++++++++++++++--------------------- 1 file changed, 423 insertions(+), 423 deletions(-) (limited to 'de-de/elixir-de.html.markdown') diff --git a/de-de/elixir-de.html.markdown b/de-de/elixir-de.html.markdown index ec933696..4acb8e23 100644 --- a/de-de/elixir-de.html.markdown +++ b/de-de/elixir-de.html.markdown @@ -1,423 +1,423 @@ ---- -language: Elixir -contributors: - - ["Joao Marques", "http://github.com/mrshankly"] -translators: - - ["Gregor Große-Bölting", "http://www.ideen-und-soehne.de"] -filename: learnelixir-de.ex -lang: de-de ---- - -Elixir ist eine moderne, funktionale Sprache für die Erlang VM. Sie ist voll -kompatibel mit Erlang, verfügt aber über eine freundlichere Syntax und bringt -viele Features mit. - -```ruby - -# Einzeilige Kommentare werden mit der Raute gesetzt. - -# Es gibt keine mehrzeiligen Kommentare; -# es ist aber problemlos möglich mehrere einzeilige Kommentare hintereinander -# zu setzen (so wie hier). - -# Mit 'iex' ruft man die Elixir-Shell auf. -# Zum kompilieren von Modulen dient der Befehl 'elixirc'. - -# Beide Befehle sollten als Umgebungsvariable gesetzt sein, wenn Elixir korrekt -# installiert wurde. - -## --------------------------- -## -- Basistypen -## --------------------------- - -# Es gibt Nummern: -3 # Integer -0x1F # Integer -3.0 # Float - -# Für bessere Lesbarkeit des Codes können Unterstriche "_" als Trennzeichen verwendet werden -1_000_000 == 1000000 # Integer -1_000.567 == 1000.567 # Float - -# Atome, das sind Literale, sind Konstanten mit Namen. Sie starten mit einem -# ':'. -:hello # Atom - -# Außerdem gibt es Tupel, deren Werte im Arbeitsspeicher vorgehalten werden. -{1,2,3} # Tupel - -# Die Werte innerhalb eines Tupels können mit der 'elem'-Funktion ausgelesen -# werden: -elem({1, 2, 3}, 0) # => 1 - -# Listen sind als verkettete Listen implementiert. -[1, 2, 3] # list - -# Auf Kopf und Rest einer Liste kann wie folgt zugegriffen werden: -[ kopf | rest ] = [1,2,3] -kopf # => 1 -rest # => [2, 3] - -# In Elixir, wie auch in Erlang, kennzeichnet '=' ein 'pattern matching' -# (Musterabgleich) und keine Zuweisung. -# Das heißt, dass die linke Seite auf die rechte Seite 'abgeglichen' wird. -# Auf diese Weise kann im Beispiel oben auf Kopf und Rest der Liste zugegriffen -# werden. - -# Ein Musterabgleich wird einen Fehler werfen, wenn die beiden Seiten nicht -# zusammenpassen. -# Im folgenden Beispiel haben die Tupel eine unterschiedliche Anzahl an -# Elementen: -{a, b, c} = {1, 2} #=> ** (MatchError) no match of right hand side value: {1,2} - -# Es gibt außerdem 'binaries', -<<1,2,3>> # binary. - -# Strings und 'char lists' -"hello" # String -'hello' # Char-Liste - -# ... und mehrzeilige Strings -""" -Ich bin ein -mehrzeiliger String. -""" -#=> "Ich bin ein\nmehrzeiliger String.\n" - -# Alles Strings werden in UTF-8 enkodiert: -"héllò" #=> "héllò" - -# Eigentlich sind Strings in Wahrheit nur binaries und 'char lists' einfach -# Listen. -<> #=> "abc" -[?a, ?b, ?c] #=> 'abc' - -# In Elixir gibt `?a` den ASCII-Integer für den Buchstaben zurück. -?a #=> 97 - -# Um Listen zu verbinden gibt es den Operator '++', für binaries nutzt man '<>' -[1,2,3] ++ [4,5] #=> [1,2,3,4,5] -'hello ' ++ 'world' #=> 'hello world' - -<<1,2,3>> <> <<4,5>> #=> <<1,2,3,4,5>> -"hello " <> "world" #=> "hello world" - -## --------------------------- -## -- Operatoren -## --------------------------- - -# Einfache Arithmetik -1 + 1 #=> 2 -10 - 5 #=> 5 -5 * 2 #=> 10 -10 / 2 #=> 5.0 - -# In Elixir gibt der Operator '/' immer einen Float-Wert zurück. - -# Für Division mit ganzzahligen Ergebnis gibt es 'div' -div(10, 2) #=> 5 - -# Um den Rest der ganzzahligen Division zu erhalten gibt es 'rem' -rem(10, 3) #=> 1 - -# Natürlich gibt es auch Operatoren für Booleans: 'or', 'and' und 'not'. Diese -# Operatoren erwarten einen Boolean als erstes Argument. -true and true #=> true -false or true #=> true -# 1 and true #=> ** (ArgumentError) argument error - -# Elixir bietet auch '||', '&&' und '!', die Argumente jedweden Typs -# akzeptieren. Alle Werte außer 'false' und 'nil' werden zu wahr evaluiert. -1 || true #=> 1 -false && 1 #=> false -nil && 20 #=> nil - -!true #=> false - -# Für Vergleiche gibt es die Operatoren `==`, `!=`, `===`, `!==`, `<=`, `>=`, -# `<` und `>` -1 == 1 #=> true -1 != 1 #=> false -1 < 2 #=> true - -# '===' und '!==' sind strikter beim Vergleich von Integern und Floats: -1 == 1.0 #=> true -1 === 1.0 #=> false - -# Es ist außerdem möglich zwei verschiedene Datentypen zu vergleichen: -1 < :hello #=> true - -# Die gesamte Ordnung über die Datentypen ist wie folgt definiert: -# number < atom < reference < functions < port < pid < tuple < list < bitstring - -# Um Joe Armstrong zu zitieren: "The actual order is not important, but that a -# total ordering is well defined is important." - -## --------------------------- -## -- Kontrollstrukturen -## --------------------------- - -# Es gibt die `if`-Verzweigung -if false do - "Dies wird nie jemand sehen..." -else - "...aber dies!" -end - -# ...und ebenso `unless` -unless true do - "Dies wird nie jemand sehen..." -else - "...aber dies!" -end - -# Du erinnerst dich an 'pattern matching'? Viele Kontrollstrukturen in Elixir -# arbeiten damit. - -# 'case' erlaubt es uns Werte mit vielerlei Mustern zu vergleichen. -case {:one, :two} do - {:four, :five} -> - "Das wird nicht passen" - {:one, x} -> - "Das schon und außerdem wird es ':two' dem Wert 'x' zuweisen." - _ -> - "Dieser Fall greift immer." -end - -# Es ist eine übliche Praxis '_' einen Wert zuzuweisen, sofern dieser Wert -# nicht weiter verwendet wird. -# Wenn wir uns zum Beispiel nur für den Kopf einer Liste interessieren: -[kopf | _] = [1,2,3] -kopf #=> 1 - -# Für bessere Lesbarkeit können wir auch das Folgende machen: -[kopf | _rest] = [:a, :b, :c] -kopf #=> :a - -# Mit 'cond' können diverse Bedingungen zur selben Zeit überprüft werden. Man -# benutzt 'cond' statt viele if-Verzweigungen zu verschachteln. -cond do - 1 + 1 == 3 -> - "Ich werde nie aufgerufen." - 2 * 5 == 12 -> - "Ich auch nicht." - 1 + 2 == 3 -> - "Aber ich!" -end - -# Es ist üblich eine letzte Bedingung einzufügen, die immer zu wahr evaluiert. -cond do - 1 + 1 == 3 -> - "Ich werde nie aufgerufen." - 2 * 5 == 12 -> - "Ich auch nicht." - true -> - "Aber ich! (dies ist im Grunde ein 'else')" -end - -# 'try/catch' wird verwendet um Werte zu fangen, die zuvor 'geworfen' wurden. -# Das Konstrukt unterstützt außerdem eine 'after'-Klausel die aufgerufen wird, -# egal ob zuvor ein Wert gefangen wurde. -try do - throw(:hello) -catch - nachricht -> "#{nachricht} gefangen." -after - IO.puts("Ich bin die 'after'-Klausel.") -end -#=> Ich bin die 'after'-Klausel. -# ":hello gefangen" - -## --------------------------- -## -- Module und Funktionen -## --------------------------- - -# Anonyme Funktionen (man beachte den Punkt) -square = fn(x) -> x * x end -square.(5) #=> 25 - -# Anonyme Funktionen unterstützen auch 'pattern' und 'guards'. Guards erlauben -# es die Mustererkennung zu justieren und werden mit dem Schlüsselwort 'when' -# eingeführt: -f = fn - x, y when x > 0 -> x + y - x, y -> x * y -end - -f.(1, 3) #=> 4 -f.(-1, 3) #=> -3 - -# Elixir bietet zahlreiche eingebaute Funktionen. Diese sind im gleichen -# Geltungsbereich ('scope') verfügbar. -is_number(10) #=> true -is_list("hello") #=> false -elem({1,2,3}, 0) #=> 1 - -# Mehrere Funktionen können in einem Modul gruppiert werden. Innerhalb eines -# Moduls ist es möglich mit dem Schlüsselwort 'def' eine Funktion zu -# definieren. -defmodule Math do - def sum(a, b) do - a + b - end - - def square(x) do - x * x - end -end - -Math.sum(1, 2) #=> 3 -Math.square(3) #=> 9 - -# Um unser einfaches Mathe-Modul zu kompilieren muss es unter 'math.ex' -# gesichert werden. Anschließend kann es mit 'elixirc' im Terminal aufgerufen -# werden: elixirc math.ex - -# Innerhalb eines Moduls definieren wir private Funktionen mit 'defp'. Eine -# Funktion, die mit 'def' erstellt wurde, kann von anderen Modulen aufgerufen -# werden; eine private Funktion kann nur lokal angesprochen werden. -defmodule PrivateMath do - def sum(a, b) do - do_sum(a, b) - end - - defp do_sum(a, b) do - a + b - end -end - -PrivateMath.sum(1, 2) #=> 3 -# PrivateMath.do_sum(1, 2) #=> ** (UndefinedFunctionError) - -# Auch Funktionsdeklarationen unterstützen 'guards' und Mustererkennung: -defmodule Geometry do - def area({:rectangle, w, h}) do - w * h - end - - def area({:circle, r}) when is_number(r) do - 3.14 * r * r - end -end - -Geometry.area({:rectangle, 2, 3}) #=> 6 -Geometry.area({:circle, 3}) #=> 28.25999999999999801048 -# Geometry.area({:circle, "not_a_number"}) -#=> ** (FunctionClauseError) no function clause matching in Geometry.area/1 - -# Wegen der Unveränderlichkeit von Variablen ist Rekursion ein wichtiger -# Bestandteil von Elixir. -defmodule Recursion do - def sum_list([head | tail], acc) do - sum_list(tail, acc + head) - end - - def sum_list([], acc) do - acc - end -end - -Recursion.sum_list([1,2,3], 0) #=> 6 - -# Elixir-Module unterstützen Attribute. Es gibt eingebaute Attribute, ebenso -# ist es möglich eigene Attribute hinzuzufügen. -defmodule MyMod do - @moduledoc """ - Dies ist ein eingebautes Attribut in einem Beispiel-Modul - """ - - @my_data 100 # Dies ist ein selbst-definiertes Attribut. - IO.inspect(@my_data) #=> 100 -end - -## --------------------------- -## -- 'Records' und Ausnahmebehandlung -## --------------------------- - -# 'Records' sind im Grunde Strukturen, die es erlauben einem Wert einen eigenen -# Namen zuzuweisen. -defrecord Person, name: nil, age: 0, height: 0 - -joe_info = Person.new(name: "Joe", age: 30, height: 180) -#=> Person[name: "Joe", age: 30, height: 180] - -# Zugriff auf den Wert von 'name' -joe_info.name #=> "Joe" - -# Den Wert von 'age' überschreiben -joe_info = joe_info.age(31) #=> Person[name: "Joe", age: 31, height: 180] - -# Der 'try'-Block wird zusammen mit dem 'rescue'-Schlüsselwort dazu verwendet, -# um Ausnahmen beziehungsweise Fehler zu behandeln. -try do - raise "Irgendein Fehler." -rescue - RuntimeError -> "Laufzeit-Fehler gefangen." - _error -> "Und dies fängt jeden Fehler." -end - -# Alle Ausnahmen haben das Attribut 'message' -try do - raise "ein Fehler" -rescue - x in [RuntimeError] -> - x.message -end - -## --------------------------- -## -- Nebenläufigkeit -## --------------------------- - -# Elixir beruht auf dem Aktoren-Model zur Behandlung der Nebenläufigkeit. Alles -# was man braucht um in Elixir nebenläufige Programme zu schreiben sind drei -# Primitive: Prozesse erzeugen, Nachrichten senden und Nachrichten empfangen. - -# Um einen neuen Prozess zu erzeugen nutzen wir die 'spawn'-Funktion, die -# wiederum eine Funktion als Argument entgegen nimmt. -f = fn -> 2 * 2 end #=> #Function -spawn(f) #=> #PID<0.40.0> - -# 'spawn' gibt eine pid (einen Identifikator des Prozesses) zurück. Diese kann -# nun verwendet werden, um Nachrichten an den Prozess zu senden. Um -# zu senden nutzen wir den '<-' Operator. Damit das alles Sinn macht müssen wir -# in der Lage sein Nachrichten zu empfangen. Dies wird mit dem -# 'receive'-Mechanismus sichergestellt: -defmodule Geometry do - def area_loop do - receive do - {:rectangle, w, h} -> - IO.puts("Area = #{w * h}") - area_loop() - {:circle, r} -> - IO.puts("Area = #{3.14 * r * r}") - area_loop() - end - end -end - -# Kompiliere das Modul, starte einen Prozess und gib die 'area_loop' Funktion -# in der Shell mit, etwa so: -pid = spawn(fn -> Geometry.area_loop() end) #=> #PID<0.40.0> - -# Sende eine Nachricht an die 'pid', die ein Muster im 'receive'-Ausdruck -# erfüllt: -pid <- {:rectangle, 2, 3} -#=> Area = 6 -# {:rectangle,2,3} - -pid <- {:circle, 2} -#=> Area = 12.56000000000000049738 -# {:circle,2} - -# Die Shell selbst ist ein Prozess und mit dem Schlüsselwort 'self' kann man -# die aktuelle pid herausfinden. -self() #=> #PID<0.27.0> - -``` - -## Referenzen und weitere Lektüre - -* [Getting started guide](http://elixir-lang.org/getting_started/1.html) auf der [elixir Website](http://elixir-lang.org) -* [Elixir Documentation](http://elixir-lang.org/docs/master/) -* ["Learn You Some Erlang for Great Good!"](http://learnyousomeerlang.com/) von Fred Hebert -* "Programming Erlang: Software for a Concurrent World" von Joe Armstrong +--- +language: Elixir +contributors: + - ["Joao Marques", "http://github.com/mrshankly"] +translators: + - ["Gregor Große-Bölting", "http://www.ideen-und-soehne.de"] +filename: learnelixir-de.ex +lang: de-de +--- + +Elixir ist eine moderne, funktionale Sprache für die Erlang VM. Sie ist voll +kompatibel mit Erlang, verfügt aber über eine freundlichere Syntax und bringt +viele Features mit. + +```ruby + +# Einzeilige Kommentare werden mit der Raute gesetzt. + +# Es gibt keine mehrzeiligen Kommentare; +# es ist aber problemlos möglich mehrere einzeilige Kommentare hintereinander +# zu setzen (so wie hier). + +# Mit 'iex' ruft man die Elixir-Shell auf. +# Zum kompilieren von Modulen dient der Befehl 'elixirc'. + +# Beide Befehle sollten als Umgebungsvariable gesetzt sein, wenn Elixir korrekt +# installiert wurde. + +## --------------------------- +## -- Basistypen +## --------------------------- + +# Es gibt Nummern: +3 # Integer +0x1F # Integer +3.0 # Float + +# Für bessere Lesbarkeit des Codes können Unterstriche "_" als Trennzeichen verwendet werden +1_000_000 == 1000000 # Integer +1_000.567 == 1000.567 # Float + +# Atome, das sind Literale, sind Konstanten mit Namen. Sie starten mit einem +# ':'. +:hello # Atom + +# Außerdem gibt es Tupel, deren Werte im Arbeitsspeicher vorgehalten werden. +{1,2,3} # Tupel + +# Die Werte innerhalb eines Tupels können mit der 'elem'-Funktion ausgelesen +# werden: +elem({1, 2, 3}, 0) # => 1 + +# Listen sind als verkettete Listen implementiert. +[1, 2, 3] # list + +# Auf Kopf und Rest einer Liste kann wie folgt zugegriffen werden: +[ kopf | rest ] = [1,2,3] +kopf # => 1 +rest # => [2, 3] + +# In Elixir, wie auch in Erlang, kennzeichnet '=' ein 'pattern matching' +# (Musterabgleich) und keine Zuweisung. +# Das heißt, dass die linke Seite auf die rechte Seite 'abgeglichen' wird. +# Auf diese Weise kann im Beispiel oben auf Kopf und Rest der Liste zugegriffen +# werden. + +# Ein Musterabgleich wird einen Fehler werfen, wenn die beiden Seiten nicht +# zusammenpassen. +# Im folgenden Beispiel haben die Tupel eine unterschiedliche Anzahl an +# Elementen: +{a, b, c} = {1, 2} #=> ** (MatchError) no match of right hand side value: {1,2} + +# Es gibt außerdem 'binaries', +<<1,2,3>> # binary. + +# Strings und 'char lists' +"hello" # String +'hello' # Char-Liste + +# ... und mehrzeilige Strings +""" +Ich bin ein +mehrzeiliger String. +""" +#=> "Ich bin ein\nmehrzeiliger String.\n" + +# Alles Strings werden in UTF-8 enkodiert: +"héllò" #=> "héllò" + +# Eigentlich sind Strings in Wahrheit nur binaries und 'char lists' einfach +# Listen. +<> #=> "abc" +[?a, ?b, ?c] #=> 'abc' + +# In Elixir gibt `?a` den ASCII-Integer für den Buchstaben zurück. +?a #=> 97 + +# Um Listen zu verbinden gibt es den Operator '++', für binaries nutzt man '<>' +[1,2,3] ++ [4,5] #=> [1,2,3,4,5] +'hello ' ++ 'world' #=> 'hello world' + +<<1,2,3>> <> <<4,5>> #=> <<1,2,3,4,5>> +"hello " <> "world" #=> "hello world" + +## --------------------------- +## -- Operatoren +## --------------------------- + +# Einfache Arithmetik +1 + 1 #=> 2 +10 - 5 #=> 5 +5 * 2 #=> 10 +10 / 2 #=> 5.0 + +# In Elixir gibt der Operator '/' immer einen Float-Wert zurück. + +# Für Division mit ganzzahligen Ergebnis gibt es 'div' +div(10, 2) #=> 5 + +# Um den Rest der ganzzahligen Division zu erhalten gibt es 'rem' +rem(10, 3) #=> 1 + +# Natürlich gibt es auch Operatoren für Booleans: 'or', 'and' und 'not'. Diese +# Operatoren erwarten einen Boolean als erstes Argument. +true and true #=> true +false or true #=> true +# 1 and true #=> ** (ArgumentError) argument error + +# Elixir bietet auch '||', '&&' und '!', die Argumente jedweden Typs +# akzeptieren. Alle Werte außer 'false' und 'nil' werden zu wahr evaluiert. +1 || true #=> 1 +false && 1 #=> false +nil && 20 #=> nil + +!true #=> false + +# Für Vergleiche gibt es die Operatoren `==`, `!=`, `===`, `!==`, `<=`, `>=`, +# `<` und `>` +1 == 1 #=> true +1 != 1 #=> false +1 < 2 #=> true + +# '===' und '!==' sind strikter beim Vergleich von Integern und Floats: +1 == 1.0 #=> true +1 === 1.0 #=> false + +# Es ist außerdem möglich zwei verschiedene Datentypen zu vergleichen: +1 < :hello #=> true + +# Die gesamte Ordnung über die Datentypen ist wie folgt definiert: +# number < atom < reference < functions < port < pid < tuple < list < bitstring + +# Um Joe Armstrong zu zitieren: "The actual order is not important, but that a +# total ordering is well defined is important." + +## --------------------------- +## -- Kontrollstrukturen +## --------------------------- + +# Es gibt die `if`-Verzweigung +if false do + "Dies wird nie jemand sehen..." +else + "...aber dies!" +end + +# ...und ebenso `unless` +unless true do + "Dies wird nie jemand sehen..." +else + "...aber dies!" +end + +# Du erinnerst dich an 'pattern matching'? Viele Kontrollstrukturen in Elixir +# arbeiten damit. + +# 'case' erlaubt es uns Werte mit vielerlei Mustern zu vergleichen. +case {:one, :two} do + {:four, :five} -> + "Das wird nicht passen" + {:one, x} -> + "Das schon und außerdem wird es ':two' dem Wert 'x' zuweisen." + _ -> + "Dieser Fall greift immer." +end + +# Es ist eine übliche Praxis '_' einen Wert zuzuweisen, sofern dieser Wert +# nicht weiter verwendet wird. +# Wenn wir uns zum Beispiel nur für den Kopf einer Liste interessieren: +[kopf | _] = [1,2,3] +kopf #=> 1 + +# Für bessere Lesbarkeit können wir auch das Folgende machen: +[kopf | _rest] = [:a, :b, :c] +kopf #=> :a + +# Mit 'cond' können diverse Bedingungen zur selben Zeit überprüft werden. Man +# benutzt 'cond' statt viele if-Verzweigungen zu verschachteln. +cond do + 1 + 1 == 3 -> + "Ich werde nie aufgerufen." + 2 * 5 == 12 -> + "Ich auch nicht." + 1 + 2 == 3 -> + "Aber ich!" +end + +# Es ist üblich eine letzte Bedingung einzufügen, die immer zu wahr evaluiert. +cond do + 1 + 1 == 3 -> + "Ich werde nie aufgerufen." + 2 * 5 == 12 -> + "Ich auch nicht." + true -> + "Aber ich! (dies ist im Grunde ein 'else')" +end + +# 'try/catch' wird verwendet um Werte zu fangen, die zuvor 'geworfen' wurden. +# Das Konstrukt unterstützt außerdem eine 'after'-Klausel die aufgerufen wird, +# egal ob zuvor ein Wert gefangen wurde. +try do + throw(:hello) +catch + nachricht -> "#{nachricht} gefangen." +after + IO.puts("Ich bin die 'after'-Klausel.") +end +#=> Ich bin die 'after'-Klausel. +# ":hello gefangen" + +## --------------------------- +## -- Module und Funktionen +## --------------------------- + +# Anonyme Funktionen (man beachte den Punkt) +square = fn(x) -> x * x end +square.(5) #=> 25 + +# Anonyme Funktionen unterstützen auch 'pattern' und 'guards'. Guards erlauben +# es die Mustererkennung zu justieren und werden mit dem Schlüsselwort 'when' +# eingeführt: +f = fn + x, y when x > 0 -> x + y + x, y -> x * y +end + +f.(1, 3) #=> 4 +f.(-1, 3) #=> -3 + +# Elixir bietet zahlreiche eingebaute Funktionen. Diese sind im gleichen +# Geltungsbereich ('scope') verfügbar. +is_number(10) #=> true +is_list("hello") #=> false +elem({1,2,3}, 0) #=> 1 + +# Mehrere Funktionen können in einem Modul gruppiert werden. Innerhalb eines +# Moduls ist es möglich mit dem Schlüsselwort 'def' eine Funktion zu +# definieren. +defmodule Math do + def sum(a, b) do + a + b + end + + def square(x) do + x * x + end +end + +Math.sum(1, 2) #=> 3 +Math.square(3) #=> 9 + +# Um unser einfaches Mathe-Modul zu kompilieren muss es unter 'math.ex' +# gesichert werden. Anschließend kann es mit 'elixirc' im Terminal aufgerufen +# werden: elixirc math.ex + +# Innerhalb eines Moduls definieren wir private Funktionen mit 'defp'. Eine +# Funktion, die mit 'def' erstellt wurde, kann von anderen Modulen aufgerufen +# werden; eine private Funktion kann nur lokal angesprochen werden. +defmodule PrivateMath do + def sum(a, b) do + do_sum(a, b) + end + + defp do_sum(a, b) do + a + b + end +end + +PrivateMath.sum(1, 2) #=> 3 +# PrivateMath.do_sum(1, 2) #=> ** (UndefinedFunctionError) + +# Auch Funktionsdeklarationen unterstützen 'guards' und Mustererkennung: +defmodule Geometry do + def area({:rectangle, w, h}) do + w * h + end + + def area({:circle, r}) when is_number(r) do + 3.14 * r * r + end +end + +Geometry.area({:rectangle, 2, 3}) #=> 6 +Geometry.area({:circle, 3}) #=> 28.25999999999999801048 +# Geometry.area({:circle, "not_a_number"}) +#=> ** (FunctionClauseError) no function clause matching in Geometry.area/1 + +# Wegen der Unveränderlichkeit von Variablen ist Rekursion ein wichtiger +# Bestandteil von Elixir. +defmodule Recursion do + def sum_list([head | tail], acc) do + sum_list(tail, acc + head) + end + + def sum_list([], acc) do + acc + end +end + +Recursion.sum_list([1,2,3], 0) #=> 6 + +# Elixir-Module unterstützen Attribute. Es gibt eingebaute Attribute, ebenso +# ist es möglich eigene Attribute hinzuzufügen. +defmodule MyMod do + @moduledoc """ + Dies ist ein eingebautes Attribut in einem Beispiel-Modul + """ + + @my_data 100 # Dies ist ein selbst-definiertes Attribut. + IO.inspect(@my_data) #=> 100 +end + +## --------------------------- +## -- 'Records' und Ausnahmebehandlung +## --------------------------- + +# 'Records' sind im Grunde Strukturen, die es erlauben einem Wert einen eigenen +# Namen zuzuweisen. +defrecord Person, name: nil, age: 0, height: 0 + +joe_info = Person.new(name: "Joe", age: 30, height: 180) +#=> Person[name: "Joe", age: 30, height: 180] + +# Zugriff auf den Wert von 'name' +joe_info.name #=> "Joe" + +# Den Wert von 'age' überschreiben +joe_info = joe_info.age(31) #=> Person[name: "Joe", age: 31, height: 180] + +# Der 'try'-Block wird zusammen mit dem 'rescue'-Schlüsselwort dazu verwendet, +# um Ausnahmen beziehungsweise Fehler zu behandeln. +try do + raise "Irgendein Fehler." +rescue + RuntimeError -> "Laufzeit-Fehler gefangen." + _error -> "Und dies fängt jeden Fehler." +end + +# Alle Ausnahmen haben das Attribut 'message' +try do + raise "ein Fehler" +rescue + x in [RuntimeError] -> + x.message +end + +## --------------------------- +## -- Nebenläufigkeit +## --------------------------- + +# Elixir beruht auf dem Aktoren-Model zur Behandlung der Nebenläufigkeit. Alles +# was man braucht um in Elixir nebenläufige Programme zu schreiben sind drei +# Primitive: Prozesse erzeugen, Nachrichten senden und Nachrichten empfangen. + +# Um einen neuen Prozess zu erzeugen nutzen wir die 'spawn'-Funktion, die +# wiederum eine Funktion als Argument entgegen nimmt. +f = fn -> 2 * 2 end #=> #Function +spawn(f) #=> #PID<0.40.0> + +# 'spawn' gibt eine pid (einen Identifikator des Prozesses) zurück. Diese kann +# nun verwendet werden, um Nachrichten an den Prozess zu senden. Um +# zu senden nutzen wir den '<-' Operator. Damit das alles Sinn macht müssen wir +# in der Lage sein Nachrichten zu empfangen. Dies wird mit dem +# 'receive'-Mechanismus sichergestellt: +defmodule Geometry do + def area_loop do + receive do + {:rectangle, w, h} -> + IO.puts("Area = #{w * h}") + area_loop() + {:circle, r} -> + IO.puts("Area = #{3.14 * r * r}") + area_loop() + end + end +end + +# Kompiliere das Modul, starte einen Prozess und gib die 'area_loop' Funktion +# in der Shell mit, etwa so: +pid = spawn(fn -> Geometry.area_loop() end) #=> #PID<0.40.0> + +# Sende eine Nachricht an die 'pid', die ein Muster im 'receive'-Ausdruck +# erfüllt: +pid <- {:rectangle, 2, 3} +#=> Area = 6 +# {:rectangle,2,3} + +pid <- {:circle, 2} +#=> Area = 12.56000000000000049738 +# {:circle,2} + +# Die Shell selbst ist ein Prozess und mit dem Schlüsselwort 'self' kann man +# die aktuelle pid herausfinden. +self() #=> #PID<0.27.0> + +``` + +## Referenzen und weitere Lektüre + +* [Getting started guide](http://elixir-lang.org/getting_started/1.html) auf der [elixir Website](http://elixir-lang.org) +* [Elixir Documentation](http://elixir-lang.org/docs/master/) +* ["Learn You Some Erlang for Great Good!"](http://learnyousomeerlang.com/) von Fred Hebert +* "Programming Erlang: Software for a Concurrent World" von Joe Armstrong -- cgit v1.2.3