Kurz: let pfad = Path.Combine(Path.GetTempPath(), “fsharp-demo.txt”) File.WriteAllLines(pfad, [ “eins”; “zwei”; “drei” ]) File.AppendAllText(pfad, “vier\n”) let zeilen = File.ReadAllLines pfad printfn “%d Zeilen.
Teil des Kurses F#
Strings
let s = "Hallo F#-Welt"
printfn "%d %s %s" s.Length (s.ToUpper()) (s.ToLower())
printfn "%c %s %s" s.[0] (s.Substring(6, 2)) s.[6..7]
printfn "%s" (s.Replace("Welt", "Erde"))
printfn "%A" (s.Split([| ' '; '-' |]))
printfn "%b %b" (s.Contains "F#") (s.StartsWith "Hallo")
printfn "%s" (String.concat ", " [ "a"; "b"; "c" ])
printfn "%s" (String.replicate 3 "ab")
printfn "[%s]" (" trim ".Trim())
printfn "%d" (s.IndexOf "F#")
printfn "%s" (System.String(Array.rev (s.ToCharArray())))
printfn "%A" (s |> Seq.filter System.Char.IsUpper |> Seq.toList)
printfn "%s" (sprintf "%05d|%-6s|%8.3f|%x|%e" 42 "li" 3.14159 255 12345.678)
printfn "%s" ((42).ToString("D5"))
printfn "%s" (System.String.Join("-", [| 1; 2; 3 |]))
let name = "Mia"
let alter = 17
printfn "%s" $"{name} ist {alter} Jahre alt, nächstes Jahr {alter + 1}"
printfn "%s" $"{3.14159:F2} | {255:X} | {1234567:N0}"
printfn "%d" (int "17" + 1)
printfn "%A" (System.Int32.TryParse "abc")
printfn "%A" (System.Int32.TryParse "42")
printfn "%s" (string (char (int 'A' + 1)))
printfn "%s" ("""Dreifache "Anführungszeichen" erlauben Text mit "Zitaten".""")
printfn "%s" (@"C:\Pfad\ohne\Escapes")Ausgabe:
13 HALLO F#-WELT hallo f#-welt
H F# F#
Hallo F#-Erde
[|"Hallo"; "F#"; "Welt"|]
true true
a, b, c
ababab
[trim]
6
tleW-#F ollaH
['H'; 'F'; 'W']
00042|li | 3.142|ff|1.234568e+004
00042
1-2-3
Mia ist 17 Jahre alt, nächstes Jahr 18
3.14 | FF | 1,234,567
18
(false, 0)
(true, 42)
B
Dreifache "Anführungszeichen" erlauben Text mit "Zitaten".
C:\Pfad\ohne\EscapesDateien
open System.IO
let pfad = Path.Combine(Path.GetTempPath(), "fsharp-demo.txt")
File.WriteAllLines(pfad, [ "eins"; "zwei"; "drei" ])
File.AppendAllText(pfad, "vier\n")
let zeilen = File.ReadAllLines pfad
printfn "%d Zeilen: %A" zeilen.Length zeilen
printfn "%d" (File.ReadAllText(pfad).Length)
for zeile in File.ReadLines pfad do
printfn "> %s" zeile
use leser = new StreamReader(pfad)
printfn "%s" (leser.ReadLine())
leser.Close()
printfn "%b %d" (File.Exists pfad) (FileInfo(pfad).Length)
File.Delete pfad
printfn "%b" (File.Exists pfad)
printfn "%s %s" (Path.GetFileName "/tmp/a/b.txt") (Path.GetExtension "b.txt")
let verz = Path.Combine(Path.GetTempPath(), "fsdir")
Directory.CreateDirectory verz |> ignore
File.WriteAllText(Path.Combine(verz, "a.txt"), "A")
File.WriteAllText(Path.Combine(verz, "b.txt"), "B")
printfn "%A" (Directory.GetFiles(verz) |> Array.map Path.GetFileName |> Array.sort)
Directory.Delete(verz, true)Ausgabe:
4 Zeilen: [|"eins"; "zwei"; "drei"; "vier"|]
20
> eins
> zwei
> drei
> vier
eins
true 20
false
b.txt .txt
[|"a.txt"; "b.txt"|]Async und Tasks
Asynchrone Abläufe schreibt man in async { } oder task { }:
let berechne n = async {
do! Async.Sleep 10
return n * n
}
let ergebnisse =
[ 1 .. 5 ]
|> List.map berechne
|> Async.Parallel
|> Async.RunSynchronously
printfn "%A" ergebnisse
let aufgabe = task {
do! System.Threading.Tasks.Task.Delay 10
return "fertig"
}
printfn "%s" aufgabe.Result
let ablauf = async {
let! a = berechne 3
let! b = berechne 4
return a + b
}
printfn "%d" (Async.RunSynchronously ablauf)
let mit_fehler = async {
try
failwith "kaputt"
return 0
with e -> return -1
}
printfn "%d" (Async.RunSynchronously mit_fehler)Ausgabe:
[|1; 4; 9; 16; 25|]
fertig
25
-1Eigene Computation Expressions
async und seq sind Computation Expressions. Mit einem Builder definiert man eigene:
type MaybeBuilder() =
member _.Bind(x, f) = Option.bind f x
member _.Return(x) = Some x
member _.ReturnFrom(x) = x
let maybe = MaybeBuilder()
let teile a b = if b = 0 then None else Some(a / b)
let rechnung a b c = maybe {
let! x = teile a b
let! y = teile x c
return x + y
}
printfn "%A" (rechnung 100 5 2)
printfn "%A" (rechnung 100 0 2)
let protokoll = ResizeArray<string>()
type LogBuilder() =
member _.Bind(x, f) = protokoll.Add(sprintf "Wert %A" x); f x
member _.Return(x) = x
let log = LogBuilder()
let r = log {
let! a = 5
let! b = a * 2
return a + b
}
printfn "%d %A" r (List.ofSeq protokoll)Ausgabe:
Some 30
None
15 ["Wert 5"; "Wert 10"]Merke
- Strings: .NET-Methoden,
sprintf,$"...", Dreifach-Anführungszeichen,@"..." - Dateien mit
System.IO.File,Path,Directory,usefür Aufräumen async { }undtask { }mitlet!/do!;Async.Parallelfür Parallelität- Computation Expressions mit eigenem Builder (
Bind,Return) bauen eigene „Syntaxen“
Übungsaufgabe
Lade mit Async.Parallel drei Dateien gleichzeitig und summiere ihre Längen.
Quiz zur Selbstkontrolle
Wie interpoliert man Strings in F#?
- $“Hallo {name}” (richtig)
- “Hallo ${name}”
- f”Hallo {name}”
- “Hallo #{name}”
Wofür ist let! in async?
- Wartet auf das Ergebnis einer asynchronen Operation (richtig)
- Deklariert eine Konstante
- Löscht Variablen
- Beendet das Programm
Was ist ein Builder?
- Ein Objekt, das das Verhalten einer Computation Expression definiert (richtig)
- Ein Compiler
- Ein Texteditor
- Ein Paketmanager
Weiter im Kurs
Zurück: Klassen, Interfaces und Module
Weiter: Praxis und Ökosystem
Alle Kapitel: F# im Überblick