Kurz: kurz = &(&1 * 2) # Capture-Syntax: &1 ist das erste Argument IO.inspect(kurz.(21)) IO.inspect(Enum.map([1, 2, 3], &(&1 + 10))) IO.inspect(Enum.map([“a”, “b”], &String.upcase/1)) # benannte Funktion als Wert
Teil des Kurses Elixir
Anonyme Funktionen
quadrat = fn x -> x * x end
plus = fn a, b -> a + b end
IO.inspect(quadrat.(7)) # Aufruf mit Punkt!
IO.inspect(plus.(2, 3))
kurz = &(&1 * 2) # Capture-Syntax: &1 ist das erste Argument
IO.inspect(kurz.(21))
IO.inspect(Enum.map([1, 2, 3], &(&1 + 10)))
IO.inspect(Enum.map(["a", "b"], &String.upcase/1)) # benannte Funktion als Wert
beschreibe = fn
0 -> "null"
n when n < 0 -> "negativ"
n when rem(n, 2) == 0 -> "gerade"
_ -> "ungerade"
end
IO.inspect(Enum.map([0, -3, 4, 7], beschreibe))
faktor = 3
mal = fn x -> x * faktor end # Closure fängt Variablen ein
faktor = 100
IO.inspect(mal.(5))Ausgabe:
49
5
42
'\v\f\r'
["A", "B"]
["null", "negativ", "gerade", "ungerade"]
15Module und benannte Funktionen
Benannte Funktionen stehen in Modulen. Mehrere Klauseln mit Pattern Matching ersetzen if-Ketten:
defmodule Mathe do
@pi 3.14159 # Modulattribut (Konstante)
def kreisflaeche(r), do: @pi * r * r
def fakultaet(0), do: 1
def fakultaet(n) when n > 0, do: n * fakultaet(n - 1)
def fib(n), do: fib(n, 0, 1)
defp fib(0, a, _), do: a # defp = privat
defp fib(n, a, b), do: fib(n - 1, b, a + b)
def gruss(name \\ "Welt", anrede \\ "Hallo") do # Standardwerte
"#{anrede}, #{name}!"
end
def groesse(liste) when is_list(liste), do: length(liste)
def groesse(map) when is_map(map), do: map_size(map)
def groesse(text) when is_binary(text), do: String.length(text)
def summe([]), do: 0
def summe([kopf | rest]), do: kopf + summe(rest)
def ggt(a, 0), do: a
def ggt(a, b), do: ggt(b, rem(a, b))
end
IO.inspect(Mathe.kreisflaeche(2))
IO.inspect(Mathe.fakultaet(20))
IO.inspect(Mathe.fib(50))
IO.puts(Mathe.gruss())
IO.puts(Mathe.gruss("Mia"))
IO.puts(Mathe.gruss("Tom", "Hi"))
IO.inspect({Mathe.groesse([1, 2]), Mathe.groesse(%{a: 1}), Mathe.groesse("Hä")})
IO.inspect(Mathe.summe([1, 2, 3, 4]))
IO.inspect(Mathe.ggt(48, 18))
IO.inspect(Mathe.__info__(:functions) |> Enum.sort() |> Enum.take(3))Ausgabe:
12.56636
2432902008176640000
12586269025
Hallo, Welt!
Hallo, Mia!
Hi, Tom!
{2, 1, 2}
10
6
[fakultaet: 1, fib: 1, ggt: 2]Funktionen werden durch Name und Stelligkeit bestimmt (fakultaet/1). Elixir hat Endrekursion-Optimierung, daher laufen auch rekursive Schleifen mit Millionen Durchläufen ohne Stapelüberlauf.
Der Pipe-Operator |>
|> reicht das Ergebnis als erstes Argument an die nächste Funktion weiter und macht Datenflüsse lesbar:
text = " Elixir macht Spaß, Elixir ist schnell! "
# Ohne Pipe (von innen nach außen lesen):
a = Enum.join(Enum.map(String.split(String.downcase(String.trim(text))), &String.capitalize/1), " ")
# Mit Pipe (von oben nach unten):
b =
text
|> String.trim()
|> String.downcase()
|> String.split()
|> Enum.map(&String.capitalize/1)
|> Enum.join(" ")
IO.puts(a)
IO.puts(a == b)
woerter =
text
|> String.downcase()
|> String.replace(~r/[^\p{L}\s]/u, "")
|> String.split()
|> Enum.frequencies()
|> Enum.sort_by(fn {w, n} -> {-n, w} end)
IO.inspect(woerter)
1..10
|> Enum.filter(&(rem(&1, 2) == 0))
|> Enum.map(&(&1 * &1))
|> Enum.sum()
|> IO.inspect()Ausgabe:
Elixir Macht Spaß, Elixir Ist Schnell!
true
[{"elixir", 2}, {"ist", 1}, {"macht", 1}, {"schnell", 1}, {"spaß", 1}]
220Import, alias, use und Dokumentation
defmodule Geometrie.Form do
@moduledoc "Hilfsfunktionen für Formen."
@doc "Berechnet die Fläche eines Rechtecks."
@spec flaeche(number, number) :: number
def flaeche(b, h), do: b * h
end
defmodule Demo do
alias Geometrie.Form # kurz: Form.flaeche
import Enum, only: [map: 2] # map ohne Präfix
def lauf do
IO.inspect(Form.flaeche(3, 4))
IO.inspect(map([1, 2], &(&1 * 3)))
end
end
Demo.lauf()
IO.inspect(Code.fetch_docs(Geometrie.Form) |> elem(0))
IO.inspect(function_exported?(Geometrie.Form, :flaeche, 2))Ausgabe:
12
[3, 6]
:error
truealiaskürzt Modulnamen,importmacht Funktionen ohne Präfix nutzbar,requirelädt Makros,usebindet Verhalten ein@doc/@moduledocsind echte Dokumentation (h Modul.funktioniniex),@specbeschreibt Typen für Dialyzer
Merke
- Anonyme Funktionen
fn x -> ... end(Aufruf mit.), Capture&(&1 + 1) - Module mit
def/defp, mehrere Klauseln mit Pattern Matching und Guards (when) - Standardwerte mit
\\, Funktionen werden über Name/Stelligkeit identifiziert - Pipe
|>reicht Ergebnisse als erstes Argument weiter alias,import,@doc,@spec
Übungsaufgabe
Schreibe Textwerkzeug.woerter_zaehlen/1, das die Wörter eines Textes mit einer Pipe zählt.
Quiz zur Selbstkontrolle
Wie ruft man eine anonyme Funktion f auf?
- f.(1) (richtig)
- f(1)
- call f(1)
- f->(1)
Was macht |> ?
- Übergibt das Ergebnis links als erstes Argument rechts (richtig)
- Verkettet Strings
- Vergleicht zwei Werte
- Startet einen Prozess
Wofür steht defp?
- Eine private Funktion (richtig)
- Eine Protokoll-Definition
- Eine Pfad-Definition
- Eine Prozess-Funktion
Weiter im Kurs
Zurück: Datentypen und Pattern Matching
Weiter: Kontrollfluss, Enum und Stream
Alle Kapitel: Elixir im Überblick