1186 lines
29 KiB
Plaintext
1186 lines
29 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "d56a820e",
|
||
"metadata": {},
|
||
"source": [
|
||
"# Grundlagen der Syntax\n",
|
||
"\n",
|
||
"## Namen von Variablen, Funktionen, Typen etc.\n",
|
||
"\n",
|
||
"- Namen können Buchstaben, Ziffern, den Unterstrich `_` und das Ausrufezeichen `!` enthalten.\n",
|
||
"- Das erste Zeichen muss ein Buchstabe oder ein Unterstrich sein.\n",
|
||
"- Groß- und Kleinbuchstaben werden unterschieden: `Nmax` und `NMAX` sind verschiedene Variablen.\n",
|
||
"- Als Zeichensatz wird [Unicode](https://home.unicode.org/) verwendet. Damit stehen über 150 Schriften und zahlreiche Symbole zur Verfügung.\n",
|
||
"- Es gibt eine kurze [Liste reservierter Schlüsselwörter](https://docs.julialang.org/en/v1/base/base/#Keywords): `if, then, function, true, false,...`\n",
|
||
"\n",
|
||
":::{.callout-tip} \n",
|
||
"## Beispiel\n",
|
||
"\n",
|
||
"zulässig: `i, x, Ω, x2, DieUnbekannteZahl, neuer_Wert, 🎷, Zähler, лічильник, einself!!!!,...`\n",
|
||
"\n",
|
||
"unzulässig: `Uwe's_Funktion, 3achsen, A#B, $this_is_not_Perl, true,...` \n",
|
||
":::\n",
|
||
"\n",
|
||
"----\n",
|
||
"\n",
|
||
":::{.callout-note }\n",
|
||
"## Anmerkung \n",
|
||
"\n",
|
||
"Neben den *reserved keywords* der Kernsprache sind zahlreiche weitere Funktionen und Objekte vordefiniert, wie z.B. die mathematischen Funktionen `sqrt(), log(), sin()`.\n",
|
||
"Diese Definitionen finden sich in dem Modul `Base`, welches Julia beim Start automatisch lädt. \n",
|
||
"Namen aus `Base` können umdefiniert werden, solange sie noch nicht verwendet wurden:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "ff07d3b4",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#| error: true \n",
|
||
"log = 3\n",
|
||
"1 + log"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "da69601f",
|
||
"metadata": {},
|
||
"source": [
|
||
"Jetzt ist natürlich der Logarithmus kaputt:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "88275d81",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#| error: true\n",
|
||
"x = log(10)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "5ecfdec6",
|
||
"metadata": {},
|
||
"source": [
|
||
"(siehe auch <https://stackoverflow.com/questions/65902105/how-to-reset-any-function-in-julia-to-its-original-state>)\n",
|
||
":::\n",
|
||
"\n",
|
||
"## Anweisungen\n",
|
||
"\n",
|
||
"- Im Normalfall enthält eine Zeile eine Anweisung.\n",
|
||
"- Wenn eine Anweisung am Zeilenende als unvollständig erkennbar ist durch \n",
|
||
" - offene Klammern\n",
|
||
" - Operationszeichen,\n",
|
||
" \n",
|
||
" dann wird die nächste Zeile als Fortsetzung aufgefasst.\n",
|
||
"- Mehrere Anweisungen pro Zeile können durch Semikolon getrennt werden.\n",
|
||
"- Im interaktiven Betrieb (REPL oder Notebook) unterdrückt ein Semikolon nach der letzten Anweisung die Ausgabe des Ergebnisses dieser Anweisung.\n",
|
||
"\n",
|
||
":::{.callout-tip}\n",
|
||
"## Beispiel \n",
|
||
"\n",
|
||
"Im interaktiven Betrieb wird der Wert der letzten Anweisung auch ohne explizites `print()` ausgegeben:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "dc76d67e",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"println(\"Hallo 🌍!\")\n",
|
||
"x = sum([i^2 for i=1:10])"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "6b068f1c",
|
||
"metadata": {},
|
||
"source": [
|
||
"Das Semikolon unterdrückt das:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "efd01a2c",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"println(\"Hallo 🌍!\")\n",
|
||
"x = sum([i^2 for i=1:10]);"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "18387226",
|
||
"metadata": {},
|
||
"source": [
|
||
":::\n",
|
||
"\n",
|
||
"---------\n",
|
||
"\n",
|
||
"\n",
|
||
":::{.callout-warning }\n",
|
||
"\n",
|
||
"Bei mehrzeiligen Anweisungen muss die fortzusetzende Zeile mit einer offenen Operation oder Klammer enden: \n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "41df7f55",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"x = sin(π/2) +\n",
|
||
" 3 * cos(0)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "61e668f9",
|
||
"metadata": {},
|
||
"source": [
|
||
"Also geht das Folgende schief, aber leider **ohne eine Fehlermeldung**!\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "694793eb",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#| error: true\n",
|
||
"#| warning: true\n",
|
||
"x = sin(π/2)\n",
|
||
" + 3 * cos(0)\n",
|
||
"println(x)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "88c64cd2",
|
||
"metadata": {},
|
||
"source": [
|
||
"Hier wird das `+` in der zweiten Zeile als Präfix-Operator (Vorzeichen) interpretiert. Damit sind 1. und 2. Zeile jeweils für sich vollständige, korrekte Ausdrücke (auch wenn die 2. Zeile natürlich völlig nutzlos ist) und werden auch so abgearbeitet. \n",
|
||
"\n",
|
||
"Moral: Wenn man längere Ausdrücke auf mehrere Zeilen aufteilen will, sollte man immer eine Klammer aufmachen. Dann ist egal, wo der Zeilenumbruch ist:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "8ec8508d",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"x = ( sin(π/2) \n",
|
||
" + 3 * cos(0) )\n",
|
||
"println(x)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "1b323891",
|
||
"metadata": {},
|
||
"source": [
|
||
":::\n",
|
||
"\n",
|
||
"\n",
|
||
"## Kommentare\n",
|
||
"\n",
|
||
"Julia kennt 2 Arten von Kommentaren im Programmtext:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "d733f6a2",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Einzeilige Kommentare beginnen mit einem Doppelkreuz.\n",
|
||
"\n",
|
||
"x = 2 # alles vom '#' bis zum Zeilenende ist ein Kommentar und wird ignoriert. x = 3"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "cf4ef498",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"#= \n",
|
||
" Ein- und mehrzeilige Kommentare können zwischen #= ... =# eingeschlossen werden.\n",
|
||
" Dabei sind verschachtelte Kommentare möglich. \n",
|
||
" #= \n",
|
||
" d.h., anders als in C/C++/Java endet der Kommentar nicht mit dem ersten \n",
|
||
" Kommentar-Endezeichen, sondern die #=...=# - Paare wirken wie Klammern. \n",
|
||
" =# \n",
|
||
" Der automatische 'syntax highlighter' weiss das leider noch nicht, wie die wechselnde \n",
|
||
" Graufärbung dieses Kommentars zeigt. \n",
|
||
"=#\n",
|
||
"\n",
|
||
"\n",
|
||
"x #= das ist ein seltener Variablenname! =# = 3 "
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "e0fc09d1",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Datentypen Teil I \n",
|
||
"\n",
|
||
"- Julia ist eine [stark typisierte](https://de.wikipedia.org/wiki/Starke_Typisierung) Sprache. Alle Objekte haben einen Typ. Funktionen/Operationen erwarten Argumente mit dem richtigen Typ.\n",
|
||
"- Julia ist eine [dynamisch typisierte](https://de.wikipedia.org/wiki/Dynamische_Typisierung) Sprache. Variablen haben keinen Typ. Sie sind Namen, die durch Zuweisung `x = ...` an Objekte gebunden werden können.\n",
|
||
"- Wenn man vom „Typ einer Variablen“ spricht, meint man den Typ des Objektes, das der Variablen gerade zugewiesen ist.\n",
|
||
"- Funktionen/Operatoren können verschiedene *methods* für verschiedene Argumenttypen implementieren.\n",
|
||
"- Abhängig von den konkreten Argumenttypen wird dann bei Verwendung einer Funktion entschieden, welche Methode benutzt wird ([*dynamic dispatch*](https://en.wikipedia.org/wiki/Dynamic_dispatch)).\n",
|
||
"\n",
|
||
"\n",
|
||
"Einfache Basistypen sind z.B.:\n",
|
||
"\n",
|
||
"```\n",
|
||
"Int64, Float64, String, Char, Bool\n",
|
||
"```\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "0ba7db71",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"x = 2\n",
|
||
"x, typeof(x), sizeof(x) "
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "ad90519a",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"x = 0.2\n",
|
||
"x, typeof(x), sizeof(x) "
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "e36334d2",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"x = \"Hallo!\"\n",
|
||
"x, typeof(x), sizeof(x) "
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "f48d35a6",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"x = 'Ω'\n",
|
||
"x, typeof(x), sizeof(x) "
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "0eb5282b",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"x = 3 > π\n",
|
||
"x, typeof(x), sizeof(x) "
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "6407ce53",
|
||
"metadata": {},
|
||
"source": [
|
||
"- `sizeof()` liefert die Größe eines Objekts oder Typs in Bytes (1 Byte = 8 Bit)\n",
|
||
"- 64bit Ganzzahlen und 64bit Gleitkommazahlen entsprechen dem Befehlssatz moderner Prozessoren und sind daher die numerischen Standardtypen.\n",
|
||
"- Zeichen/*chars* `'A'` und Zeichenketten/*strings* `\"A\"` der Länge 1 sind verschiedene Objekte. \n",
|
||
"\n",
|
||
"## Ablaufsteuerung\n",
|
||
"\n",
|
||
"### `if`-Blöcke\n",
|
||
"\n",
|
||
"- Ein `if`-Block *kann* **beliebig viele** `elseif`-Zweige und als letztes maximal **einen** `else`-Zweig enthalten.\n",
|
||
"- Der Block hat einen Wert, den Wert der letzten ausgeführten Anweisung.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "d2c3f6c8",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"x = 33\n",
|
||
"y = 44\n",
|
||
"z = 34\n",
|
||
"\n",
|
||
"if x < y && z != x # elseif- und else-Blöcke sind optional\n",
|
||
" println(\"yes\")\n",
|
||
" x += 10\n",
|
||
"elseif x < z # beliebig viele elseif-Blöcke\n",
|
||
" println(\" x is smaller than z\")\n",
|
||
"elseif x == z+1 \n",
|
||
" println(\" x is successor of z\")\n",
|
||
"else # maximal ein else-Block \n",
|
||
" println(\"Alles falsch\")\n",
|
||
"end # Wert des gesamten Blocks ist der Wert der \n",
|
||
" # letzten ausgeführten Auswertung"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "868ae573",
|
||
"metadata": {},
|
||
"source": [
|
||
"Kurze Blöcke kann man in eine Zeile schreiben:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "76f17f5f",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"if x > 10 println(\"x is larger than 10\") end "
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "ef1e84b5",
|
||
"metadata": {},
|
||
"source": [
|
||
"Der Wert eines `if`-Blocks kann natürlich zugewiesen werden:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "318501e9",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"y = 33\n",
|
||
"z = if y > 10 \n",
|
||
" println(\"y is larger than 10\") \n",
|
||
" y += 1 \n",
|
||
" end\n",
|
||
"z "
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "0c05b161",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Auswahloperator (ternary operator) `test ? exp1 : exp2`\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "40e9db00",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"x = 20\n",
|
||
"y = 15\n",
|
||
"z = x < y ? x+1 : y+1"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "48705675",
|
||
"metadata": {},
|
||
"source": [
|
||
"ist äquivalent zu\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "dadac914",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"z = if x < y\n",
|
||
" x+1\n",
|
||
" else\n",
|
||
" y+1\n",
|
||
" end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "8d122010",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Vergleiche, Tests, Logische Operationen\n",
|
||
"\n",
|
||
"### Arithmetische Vergleiche\n",
|
||
"\n",
|
||
"- `==`\n",
|
||
"- `!=`, `≠`\n",
|
||
"- `>`\n",
|
||
"- `>=`, `≥`\n",
|
||
"- `<`\n",
|
||
"- `<=`, `≤`\n",
|
||
"\n",
|
||
"Wie üblich, ist der Test auf Gleichheit `==` vom Zuweisungsoperator `=` zu unterscheiden. Vergleichen lässt sich so gut wie alles:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "13005342",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"\"Aachen\" < \"Leipzig\", 10 ≤ 10.01, [3,4,5] < [3,6,2]"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "dd31f487",
|
||
"metadata": {},
|
||
"source": [
|
||
"Nun ja, fast alles:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "7491b44b",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"3 < \"vier\""
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "d5eace21",
|
||
"metadata": {},
|
||
"source": [
|
||
"Die Fehlermeldung zeigt ein paar Grundprinzipien von Julia:\n",
|
||
"\n",
|
||
"- Operatoren sind auch nur Funktionen: `x < y` wird zum Funktionsaufruf `isless(x, y)`.\n",
|
||
"- Funktionen (und damit Operatoren) können verschiedene *methods* für verschiedene Argumenttypen implementieren. \n",
|
||
"- Abhängig von den konkreten Argumenttypen wird beim Aufruf der Funktion entschieden, welche Methode benutzt wird ([*dynamic dispatch*](https://en.wikipedia.org/wiki/Dynamic_dispatch)).\n",
|
||
"\n",
|
||
"Man kann sich alle Methoden zu einer Funktion anzeigen lassen. Das gibt einen Einblick in das komplexe Typssystem von Julia:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "6538caaf",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"methods(<)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "297ce845",
|
||
"metadata": {},
|
||
"source": [
|
||
"Zuletzt noch: Vergleiche können gekettet werden.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "449eba70",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"10 < x ≤ 100 # das ist äquivalent zu\n",
|
||
" # 10 < x && x ≤ 100"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "9f4b1c41",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Tests \n",
|
||
"Einge Funktionen vom Typ `f(c::Char) -> Bool`\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "18d77ec1",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"isnumeric('a'), isnumeric('7'), isletter('a')"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "2dc1c0aa",
|
||
"metadata": {},
|
||
"source": [
|
||
"und vom Typ `f(s1::String, s2::String) -> Bool`\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "ea9be46e",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"contains(\"Lampenschirm\", \"pensch\"), startswith(\"Lampenschirm\", \"Lamb\"), endswith(\"Lampenschirm\", \"rm\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "af8b3ce6",
|
||
"metadata": {},
|
||
"source": [
|
||
"- Die Funktion `in(item, collection) -> Bool` testet, ob `item` in `collection` ist. \n",
|
||
"- Sie hat auch das Alias ` ∈(item, collection)` und \n",
|
||
"- sowohl `in` als auch `∈` können auch als Infix-Operatoren geschrieben werden.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "e811c4d8",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"x = 3\n",
|
||
"x in [1, 2, 3, 4, 5]"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "15f8ba27",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"x ∈ [1, 2, 33, 4, 5]"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "6b811515",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Logische Operationen: `&&`, `||`, `!`\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "ea9ad7fb",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"3 < 4 && !(2 > 8) && !contains(\"aaa\", \"b\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "a1886e91",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### Bedingte Auswertung (_short circuit evaluation_)\n",
|
||
"\n",
|
||
"- in `a && b` wird `b` nur ausgewertet, wenn `a == true`\n",
|
||
"- in `a || b` wird `b` nur ausgewertet, wenn `a == false`\n",
|
||
"\n",
|
||
"(i) Damit kann `if test statement end` auch als `test && statement` geschrieben werden.\n",
|
||
"\n",
|
||
"(ii) Damit kann `if !test statement end` als `test || statement` geschrieben werden.\n",
|
||
"\n",
|
||
"Als Beispiel^[aus der [Julia-Dokumentation](https://docs.julialang.org/en/v1/manual/control-flow/#Short-Circuit-Evaluation)] hier eine Implementierung der Fakultätsfunktion *(factorial)*:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "a5ef06bf",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"function fact(n::Int)\n",
|
||
" n >= 0 || error(\"n must be non-negative\")\n",
|
||
" n == 0 && return 1\n",
|
||
" n * fact(n-1)\n",
|
||
"end\n",
|
||
"\n",
|
||
"fact(5)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "bb950743",
|
||
"metadata": {},
|
||
"source": [
|
||
"Natürlich kann man alle diese Tests auch Variablen vom Typ `Bool` zuordnen und\n",
|
||
"diese Variablen können als Tests in `if`- und `while`-Blöcken verwendet werden:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "8c44f3bc",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"x = 3 < 4\n",
|
||
"y = 5 ∈ [1, 2, 5, 7]\n",
|
||
"z = x && y\n",
|
||
"if z # äquivalent zu: if 3 < 4 && 5 in [1,2,5,7]\n",
|
||
" println(\"Stimmt alles!\")\n",
|
||
"end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "b7d1e766",
|
||
"metadata": {},
|
||
"source": [
|
||
"- In Julia müssen alle Tests in einem logischen Ausdruck vom Typ `Bool` sein.\n",
|
||
"- Es gibt keine implizite Konvertierung à la *\"0 is false and 1 (or anything != 0) is true\"*\n",
|
||
"- Wenn `x` ein numerischer Typ ist, dann muss daher das C-Idiom `if(x)` als `if x != 0` geschrieben werden.\n",
|
||
"- Es gibt eine Ausnahme zur Unterstützung der _short circuit evaluation_:\n",
|
||
" - bei den Konstrukten `a && b && c...` bzw `a || b || c...` muss der letzte Teilausdruck nicht vom Typ `Bool` sein, wenn diese Konstrukte nicht als Tests in `if` oder `while` verwendet werden:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "0a46fa2b",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"z = 3 < 4 && 10 < 5 && sqrt(3^3)\n",
|
||
"z, typeof(z)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "f56bbc75",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"z = 3 < 4 && 10 < 50 && sqrt(3^3)\n",
|
||
"z, typeof(z)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "508cebd9",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Schleifen *(loops)*\n",
|
||
"\n",
|
||
"### Die `while` (\"solange\")-Schleife\n",
|
||
"\n",
|
||
"\n",
|
||
"Syntax:\n",
|
||
"```\n",
|
||
"while *condition*\n",
|
||
" *loop body*\n",
|
||
"end\n",
|
||
"```\n",
|
||
"Eine Reihe von Anweisungen (der Schleifenkörper) wird immer wieder abgearbeitet, solange eine Bedingung erfüllt ist.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "d91b98b6",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"i = 1 # typischerweise braucht der Test der \n",
|
||
" # while-Schleife eine Vorbereitung ...\n",
|
||
"while i < 10 \n",
|
||
" println(i)\n",
|
||
" i += 2 # ... und ein update\n",
|
||
"end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "f7edea21",
|
||
"metadata": {},
|
||
"source": [
|
||
"Der Körper einer `while`- und `for`-Schleife kann die Anweisungen `break` und `continue` enthalten. `break` stoppt die Schleife, `continue` überspringt den Rest des Schleifenkörpers und beginnt sofort mit dem nächsten Schleifendurchlauf.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "149c79ac",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"i = 0\n",
|
||
"\n",
|
||
"while i<10\n",
|
||
" i += 1\n",
|
||
"\n",
|
||
" if i == 3\n",
|
||
" continue # beginne sofort nächsten Durchlauf,\n",
|
||
" end # überspringe Rest des Schleifenkörpers\n",
|
||
"\n",
|
||
" println(\"i = $i\")\n",
|
||
"\n",
|
||
" if i ≥ 5\n",
|
||
" break # breche Schleife ab\n",
|
||
" end\n",
|
||
"end\n",
|
||
"\n",
|
||
"println(\"Fertig!\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "2e91f7a3",
|
||
"metadata": {},
|
||
"source": [
|
||
"Mit `break` kann man auch Endlosschleifen verlassen:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "0b1b1ab2",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"i = 1\n",
|
||
"\n",
|
||
"while true\n",
|
||
" println(2^i)\n",
|
||
" i += 1\n",
|
||
" if i > 8 break end\n",
|
||
"end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "d9bc10da",
|
||
"metadata": {},
|
||
"source": [
|
||
"### `for`-Schleifen\n",
|
||
"\n",
|
||
"Syntax:\n",
|
||
"\n",
|
||
"```\n",
|
||
"for *var* in *iterable container*\n",
|
||
" *loop body*\n",
|
||
"end\n",
|
||
"```\n",
|
||
"\n",
|
||
"Der Schleifenkörper wird für alle Items aus einem Container durchlaufen. \n",
|
||
"\n",
|
||
"Statt `in` kann immer auch $\\in$ verwendet werden. Im Kopf einer `for`-Schleife kann auch `=` verwendet werden.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "99cd73cb",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"for i ∈ [\"Mutter\", \"Vater\", \"Tochter\"]\n",
|
||
" println(i)\n",
|
||
"end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "1a17064c",
|
||
"metadata": {},
|
||
"source": [
|
||
"Oft benötigt man einen numerischen Schleifenzähler. Dafür gibt es das *range*-Konstrukt. Die einfachsten Formen sind \n",
|
||
"`Start:Ende` und `Start:Schrittweite:Ende`. \n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "3177977b",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"endwert = 5\n",
|
||
"\n",
|
||
"for i ∈ 1:endwert\n",
|
||
" println(i^2)\n",
|
||
"end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "0c859acc",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"for i = 1:5.5 print(\" $i\") end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "c31d91f6",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"for i = 1:2:14 print(\" $i\") end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "c35be84d",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"for k = 14 : -2.5 : 1 print(\" $k\") end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "19034238",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### Geschachtelte Schleifen _(nested loops)_\n",
|
||
"\n",
|
||
"Ein `break` beendet die innerste Schleife.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "9be68ac5",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"for i = 1:3\n",
|
||
" for j = 1:3\n",
|
||
" println( (i,j) )\n",
|
||
" if j == 2\n",
|
||
" break\n",
|
||
" end\n",
|
||
" end\n",
|
||
"end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "99328006",
|
||
"metadata": {},
|
||
"source": [
|
||
"Man kann *nested loops* auch in einer `for`-Anweisung zusammenfassen. Dann beendet ein `break` die Gesamtschleife.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "e437369c",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"for i = 1:3, j=1:3 # im Prinzip dasselbe wie oben, aber:\n",
|
||
" println( (i,j) )\n",
|
||
" if j == 2\n",
|
||
" break # break bricht hier die Gesamtschleife ab\n",
|
||
" end\n",
|
||
"end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "e995a233",
|
||
"metadata": {},
|
||
"source": [
|
||
":::{.callout-important .titlenormalxx}\n",
|
||
"## **Wichtig:** Die Semantik ist völlig anders, als bei C-artigen `for`-Schleifen!\n",
|
||
"\n",
|
||
"**Bei jedem Schleifendurchlauf wird die Laufvariable neu mit dem nächsten Element aus dem Container initialisiert.**\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "2d2e2164",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"for i = 1:5\n",
|
||
" print(i,\" ... \")\n",
|
||
" i += 2\n",
|
||
" println(i)\n",
|
||
"end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "6c940891",
|
||
"metadata": {},
|
||
"source": [
|
||
"-------\n",
|
||
"\n",
|
||
"Die C-Semantik von `for(i=1; i<5; i++)` entspricht der `while`-Schleife:\n",
|
||
"```\n",
|
||
"i = 1\n",
|
||
"while i<5\n",
|
||
" *loop body* # hier kann auch wirksam an i rumgepfuscht werden\n",
|
||
" i += 1\n",
|
||
"end\n",
|
||
"```\n",
|
||
":::\n",
|
||
"\n",
|
||
"## Unicode \n",
|
||
"\n",
|
||
"Julia verwendet Unicode als Zeichensatz. Damit können für Variablen, Funktionen etc auch Bezeichner aus nicht-lateinischen Schriften (zB Kyrillisch, Koreanisch, Sanskrit, Runen,\n",
|
||
"Emoji,...) verwendet werden. Die Frage, wie man solche Zeichen in seinem Editor eingeben kann und ob der verwendete Bildschirm-Font sie darstellen kann, ist nicht Julias Problem.\n",
|
||
"\n",
|
||
"- Einige Unicode-Zeichen, z.B. `≤, ≠, ≥, π, ∈, √`, können anstelle von `<=, !=, >=, pi, in, sqrt` verwendet werden. \n",
|
||
"\n",
|
||
"- über 3000 Unicode-Zeichen können in Julia in einer LaTeX-ähnlichen Weise mit der Tab-Vervollständigung eingegeben werden. \n",
|
||
" - `\\alpha<TAB>` wird zu `α`, \n",
|
||
" - `\\euler<TAB>` wird zu `ℯ` (Eulersche Zahl `exp(1)`, [spezielles Schreibschrift-e, `U+0212F`](https://www.htmlsymbol.com/unicode-code/212f.html))\n",
|
||
" - `\\le<TAB>` wird zu `≤`,\n",
|
||
" - `\\in<TAB>` wird zu `∈`,\n",
|
||
" - `\\:rainbow:<TAB>` wird zu `🌈` \n",
|
||
" [Hier geht es zur Liste.](https://docs.julialang.org/en/v1/manual/unicode-input/)\n",
|
||
"\n",
|
||
"## Eigenheiten und Stolperfallen der Syntax\n",
|
||
"\n",
|
||
"- Man kann den Multiplikationsoperator `*` nach einer numerischen Konstanten weglassen, wenn eine Variable, Funktion oder öffnende Klammer folgt.\n",
|
||
" ```\n",
|
||
" z = 3.4x + 2(x+y) + xy\n",
|
||
" ```\n",
|
||
"\n",
|
||
"ist daher korrektes Julia. Beachte allerdings, dass der Term `xy` als eine Variable mit dem Namen xy interpretiert wird __und nicht__ als Produkt von x und y!\n",
|
||
"\n",
|
||
"- Diese Regel hat ein paar Tücken:\n",
|
||
"\n",
|
||
"Das funktioniert wie erwartet:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "9d8ee587",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"e = 7\n",
|
||
"3e "
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "4a3975ec",
|
||
"metadata": {},
|
||
"source": [
|
||
"Hier wird die Eingabe als Gleitkommazahl interpretiert -- und `3E+2` oder `3f+2` (Float32) ebenso. \n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "fa68ebcd",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"3e+2 "
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "d3b54ba7",
|
||
"metadata": {},
|
||
"source": [
|
||
"Ein Leerzeichen schafft Eindeutigkeit:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "378e3e06",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"3e + 2 "
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "d23bc72e",
|
||
"metadata": {},
|
||
"source": [
|
||
"Das funktioniert:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "ab2811f6",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"x = 4\n",
|
||
"3x + 3 "
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "c81689d3",
|
||
"metadata": {},
|
||
"source": [
|
||
"...und das nicht. `0x`, `0o`, `0b` wird als Anfang einer Hexadezimal-, Oktal- bzw. Binärkonstanten interpretiert.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "a5eff7fc",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"3y + 0x "
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "ac739eda",
|
||
"metadata": {},
|
||
"source": [
|
||
"- Es gibt noch ein paar andere Fälle, bei denen die sehr kulante Syntax zu Überraschungen führt.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "a69f9e83",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"Wichtig = 21\n",
|
||
"Wichtig! = 42 # Bezeichner können auch ein ! enthalten\n",
|
||
"(Wichtig, Wichtig!)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "3d9dc81e",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"Wichtig!=88"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "89722987",
|
||
"metadata": {},
|
||
"source": [
|
||
"Julia interpretiert das als Vergleich `Wichtig != 88`.\n",
|
||
"\n",
|
||
"Leerzeichen helfen:\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "87a6cfd7",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"Wichtig! = 88\n",
|
||
"Wichtig!"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "90ae7dac",
|
||
"metadata": {},
|
||
"source": [
|
||
"- Operatoren der Form `.*`, `.+`,... haben in Julia eine spezielle Bedeutung (*broadcasting*, d.h., vektorisierte Operationen). \n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "538cd36e",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"1.+2."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "7f39acd9",
|
||
"metadata": {},
|
||
"source": [
|
||
"Wieder gilt: Leerzeichen schaffen Klarheit!\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "45ceb4be",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"1. + 2."
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": "Julia 1.8.5",
|
||
"language": "julia",
|
||
"name": "julia-1.8"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 5
|
||
}
|