Funktionale Programmierung für .NET
Ausführen: Datei Program.fs in einem Projekt (dotnet new console -lang F#) speichern und mit dotnet run ausführen; Skripte mit dotnet fsi skript.fsx (.NET SDK von dotnet.microsoft.com).
let bindet unveränderlich, mutable und <- erlauben Änderungprintfn "%d %s" ist typsicher; $"..." interpoliertdotnet new console -lang "F#" -o hallo # Projekt anlegen
cd hallo && dotnet run # bauen und starten
dotnet fsi # interaktive Konsole (F# Interactive)
dotnet fsi skript.fsx # Skript ausführen
dotnet add package FSharp.Data # NuGet-Paketlet f x y = ..., curryt, partiell anwendbar; >> komponiert, |> verkettetif/elif/else sind Ausdrücke; match mit Mustern und Wächtern (when)let rec; for/while für imperativen Stillet quadrat x = x * x
let addiere a b = a + b
let begruesse (name: string) = "Hallo, " + name + "!"
let plus10 = addiere 10
let verdopple = fun x -> x * 2
printfn "%d %d" (quadrat 7) (addiere 3 4)
printfn "%s" (begruesse "Mia")
printfn "%d" (plus10 5)
printfn "%d" (verdopple 21)
let zweimal f x = f (f x)
printfn "%d" (zweimal verdopple 5)
let komponiert = quadrat >> verdopple
printfn "%d" (komponiert 3)
printfn "%d" (3 |> quadrat |> verdopple)
let rec fak n = if n <= 1 then 1 else n * fak (n - 1)
let rec fib a b i = if i = 0 then a else fib b (a + b) (i - 1)
printfn "%d %d" (fak 10) (fib 0 1 40)
let teile a b = a / b, a % b // Tupel als Rückgabe
let q, r = teile 17 5
printfn "%d %d" q r
let inline addiereAlles (x: ^a) (y: ^a) = x + y
printfn "%d %.1f" (addiereAlles 1 2) (addiereAlles 1.5 2.5)[1; 2; 3]), Arrays ([| ... |]), Maps, Sets und Sequenzen (seq)List (und Array, Seq) bietet map, filter, fold, sortBy, groupBy, ...[], kopf :: restlet l = [ 5; 3; 9; 1; 7 ]
printfn "%A" l
printfn "%d %d %d" l.Length l.Head (List.last l)
printfn "%A" (0 :: l)
printfn "%A" (l @ [ 8; 9 ])
printfn "%A" (List.rev l)
printfn "%A" (List.sort l)
printfn "%A" (List.sortDescending l)
printfn "%A" (List.map (fun x -> x * 2) l)
printfn "%A" (List.filter (fun x -> x > 4) l)
printfn "%d %d" (List.sum l) (List.max l)
printfn "%d" (List.fold (fun acc x -> acc + x) 0 l)
printfn "%d" (List.reduce max l)
printfn "%A" (List.tryFind (fun x -> x > 5) l)
printfn "%A" (List.tryFind (fun x -> x > 50) l)
printfn "%b %b" (List.exists (fun x -> x > 8) l) (List.forall (fun x -> x > 0) l)
printfn "%A" (List.take 2 l)
printfn "%A" (List.skip 3 l)
printfn "%A" (List.zip [ 1; 2; 3 ] [ "a"; "b"; "c" ])
printfn "%A" (List.partition (fun x -> x % 2 = 0) [ 1 .. 6 ])
printfn "%A" (List.groupBy (fun x -> x % 3) [ 1 .. 7 ])
printfn "%A" (List.collect (fun x -> [ x; x ]) [ 1; 2 ])
printfn "%A" (List.distinct [ 1; 2; 2; 3; 3; 3 ])
printfn "%A" (List.chunkBySize 2 [ 1 .. 5 ])
printfn "%A" (List.windowed 2 [ 1; 2; 3; 4 ])
printfn "%A" (List.init 5 (fun i -> i * i))
printfn "%A" [ for i in 1 .. 5 -> i * i ]
printfn "%A" [ for i in 1 .. 10 do if i % 2 = 0 then yield i ]
printfn "%A" (List.sortBy (fun s -> String.length s) [ "ccc"; "a"; "bb" ])
printfn "%A" (List.pairwise [ 1; 2; 3 ])
printfn "%A" (List.countBy (fun x -> x % 2 = 0) [ 1; 2; 3; 4; 5 ]){ Name = ...}) sind unveränderlich; { r with ... } kopiert mit Änderungmatch wird vollständig geprüftoption und Result ersetzen null und Ausnahmen bei erwartbaren Fehlern<m>) erweitern die Ausdruckskrafttype Person = { Name: string; Alter: int }
let p = { Name = "Mia"; Alter = 17 }
let p2 = { p with Alter = 18 }
printfn "%A" p
printfn "%A" p2
printfn "%b" (p = { Name = "Mia"; Alter = 17 })
printfn "%s ist %d" p.Name p.Alter
let { Name = n; Alter = a } = p2
printfn "%s %d" n a
type Punkt = { X: float; Y: float }
let abstand (a: Punkt) (b: Punkt) = sqrt ((a.X - b.X) ** 2.0 + (a.Y - b.Y) ** 2.0)
printfn "%.1f" (abstand { X = 0.0; Y = 0.0 } { X = 3.0; Y = 4.0 })
type Konto =
{ Inhaber: string
mutable Stand: decimal }
member this.Einzahlen(betrag) = this.Stand <- this.Stand + betrag
override this.ToString() = sprintf "%s: %M" this.Inhaber this.Stand
let k = { Inhaber = "Mia"; Stand = 100m }
k.Einzahlen 25.5m
printfn "%O" kmember, abstract/default/override, inheritinterface ... with, Objektausdrücke { new ... }module) gruppieren Code; Operatoren lassen sich auf Typen überladen'T) mit Constraints (when 'a: comparison) und inlinetype Tier(name: string) =
member _.Name = name
abstract Laut: unit -> string
default _.Laut() = "..."
member this.Vorstellen() = sprintf "%s sagt %s" name (this.Laut())
type Hund(name: string) =
inherit Tier(name)
override _.Laut() = "Wau"
type Katze(name: string) =
inherit Tier(name)
override _.Laut() = "Miau"
let tiere: Tier list = [ Hund "Rex"; Katze "Mimi"; Tier "Fisch" ]
for t in tiere do printfn "%s" (t.Vorstellen())
type Zaehler() =
let mutable n = 0
member _.Erhoehe() = n <- n + 1
member _.Wert = n
let z = Zaehler()
z.Erhoehe()
z.Erhoehe()
printfn "%d" z.Wert
printfn "%b" (tiere.[0] :? Hund)sprintf, $"...", Dreifach-Anführungszeichen, @"..."System.IO.File, Path, Directory, use für Aufräumenasync { } und task { } mit let!/do!; Async.Parallel für ParallelitätBind, Return) bauen eigene „Syntaxen“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")|>) und Records/Unions machen Code kurz und lesbartry ... with, exception und failwith// Primzahlsieb
let sieb n =
let prim = Array.create (n + 1) true
for i in 2 .. int (sqrt (float n)) do
if prim.[i] then
for j in i * i .. i .. n do prim.[j] <- false
[ for i in 2 .. n do if prim.[i] then yield i ]
printfn "%A" (sieb 50)
printfn "%d" (List.length (sieb 10000))
// Caesar
let verschiebe (text: string) schluessel =
text
|> String.map (fun c ->
if System.Char.IsLower c then char ((int c - int 'a' + schluessel + 26) % 26 + int 'a')
elif System.Char.IsUpper c then char ((int c - int 'A' + schluessel + 26) % 26 + int 'A')
else c)
let geheim = verschiebe "Hallo F#!" 3
printfn "%s" geheim
printfn "%s" (verschiebe geheim -3)let zeile (name: string) (wert: string) = printfn "%-26s %s" name wert
zeile "List.sum [1;2;3]" (string (List.sum [ 1; 2; 3 ]))
zeile "Seq.toList { 1..3 }" (sprintf "%A" (Seq.toList { 1 .. 3 }))
zeile "[1;2] @ [3]" (sprintf "%A" ([ 1; 2 ] @ [ 3 ]))
zeile "List.rev [1;2;3]" (sprintf "%A" (List.rev [ 1; 2; 3 ]))
zeile "Some 5 |> Option.map ((+) 1)" (sprintf "%A" (Some 5 |> Option.map ((+) 1)))
zeile "(1, 2) ||> (+)" (string ((1, 2) ||> (+)))
zeile "id 7, ignore 7" (sprintf "%d %A" (id 7) (ignore 7))
zeile "fst (1,2), snd (1,2)" (sprintf "%d %d" (fst (1, 2)) (snd (1, 2)))
zeile "min 3 9, max 3 9" (sprintf "%d %d" (min 3 9) (max 3 9))
zeile "string 3.5, float 2" (sprintf "%s %f" (string 3.5) (float 2))
zeile "Array.init 3 id" (sprintf "%A" (Array.init 3 id))
zeile "typeof<int>.Name" typeof<int>.Name