JuliaKurs23/nb/syntax.ipynb

1186 lines
29 KiB
Plaintext
Raw Normal View History

2023-05-12 20:12:56 +02:00
{
"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
}