Variantentypen
Ein Variantentyp beschreibt „entweder A oder B oder C“, oft mit Daten pro Fall. Der Compiler prüft, dass match alle Fälle behandelt:
type farbe = Rot | Gruen | Blau
type form =
| Kreis of float
| Rechteck of float * float
| Dreieck of float * float * float
let farbname = function
| Rot -> "rot"
| Gruen -> "grün"
| Blau -> "blau"
let flaeche = function
| Kreis r -> 3.14159 *. r *. r
| Rechteck (b, h) -> b *. h
| Dreieck (a, b, c) ->
let s = (a +. b +. c) /. 2.0 in
sqrt (s *. (s -. a) *. (s -. b) *. (s -. c))
let () =
print_endline (farbname Gruen);
List.iter (fun f -> Printf.printf "%.2f\n" (flaeche f))
[Kreis 1.0; Rechteck (2.0, 3.0); Dreieck (3.0, 4.0, 5.0)]Ausgabe
grün 3.14 6.00 6.00
Rekursive Typen: Ausdrücke und Bäume
type ausdruck =
| Zahl of int
| Plus of ausdruck * ausdruck
| Mal of ausdruck * ausdruck
| Neg of ausdruck
let rec eval = function
| Zahl n -> n
| Plus (a, b) -> eval a + eval b
| Mal (a, b) -> eval a * eval b
| Neg a -> - (eval a)
let rec zeige = function
| Zahl n -> string_of_int n
| Plus (a, b) -> "(" ^ zeige a ^ " + " ^ zeige b ^ ")"
| Mal (a, b) -> zeige a ^ " * " ^ zeige b
| Neg a -> "-" ^ zeige a
type 'a baum = Blatt | Knoten of 'a baum * 'a * 'a baum
let rec einfuegen x = function
| Blatt -> Knoten (Blatt, x, Blatt)
| Knoten (l, w, r) as k ->
if x < w then Knoten (einfuegen x l, w, r)
else if x > w then Knoten (l, w, einfuegen x r)
else k
let rec in_reihenfolge = function
| Blatt -> []
| Knoten (l, w, r) -> in_reihenfolge l @ [w] @ in_reihenfolge r
let rec hoehe = function
| Blatt -> 0
| Knoten (l, _, r) -> 1 + max (hoehe l) (hoehe r)
let () =
let e = Mal (Plus (Zahl 1, Zahl 2), Neg (Zahl 4)) in
Printf.printf "%s = %d\n" (zeige e) (eval e);
let b = List.fold_left (fun acc x -> einfuegen x acc) Blatt [5; 3; 8; 1; 4; 7; 9; 3] in
List.iter (Printf.printf "%d ") (in_reihenfolge b);
print_newline ();
Printf.printf "Höhe %d\n" (hoehe b)Ausgabe
(1 + 2) * -4 = -12 1 3 4 5 7 8 9 Höhe 3
'a baum ist ein polymorpher Typ: Der Baum funktioniert für jeden Elementtyp.
Result: Fehler als Werte
type fehler = Division_durch_null | Negativ of int
let teile a b = if b = 0 then Error Division_durch_null else Ok (a / b)
let wurzel n = if n < 0 then Error (Negativ n) else Ok (int_of_float (sqrt (float_of_int n)))
let berechne a b =
Result.bind (teile a b) (fun q -> wurzel q)
let melde = function
| Ok v -> Printf.printf "Ok %d\n" v
| Error Division_durch_null -> print_endline "Fehler: durch null"
| Error (Negativ n) -> Printf.printf "Fehler: %d negativ\n" n
let () =
melde (berechne 100 4);
melde (berechne 1 0);
melde (berechne (-16) 2)Ausgabe
Ok 5 Fehler: durch null Fehler: -8 negativ
Ausnahmen
Für unerwartete Fehler gibt es Exceptions:
exception Eigener_fehler of string
let pruefe n = if n < 0 then raise (Eigener_fehler "negativ") else n
let () =
(try ignore (pruefe (-1)) with Eigener_fehler m -> print_endline ("gefangen: " ^ m));
(try ignore (10 / 0) with Division_by_zero -> print_endline "durch null");
(try ignore (List.hd []) with Failure m -> print_endline ("Failure: " ^ m));
(try ignore (int_of_string "abc") with Failure m -> print_endline m);
(try ignore (Hashtbl.find (Hashtbl.create 1) "x") with Not_found -> print_endline "nicht gefunden")Ausgabe
gefangen: negativ durch null Failure: hd int_of_string nicht gefunden
Merke
type t = A | B of intdefiniert Varianten;matchwird vollständig geprüft- Rekursive und polymorphe (
'a) Typen modellieren Ausdrücke und Bäume result(Ok/Error) für erwartbare Fehler,exceptionfür Ausnahmenas,whenund verschachtelte Muster machenmatchmächtig
Aufgabe
Erweitere ausdruck um Division und gib bei Division durch null ein Error zurück.