EMZETT.
Login

Kurz: Ein Variantentyp beschreibt „entweder A oder B oder C“, oft mit Daten pro Fall. Der Compiler prüft, dass match alle Fälle behandelt:

Teil des Kurses OCaml

Kapitel 4 von 8 im Kurs OCaml. Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

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 int definiert Varianten; match wird vollständig geprüft
  • Rekursive und polymorphe ('a) Typen modellieren Ausdrücke und Bäume
  • result (Ok/Error) für erwartbare Fehler, exception für Ausnahmen
  • as, when und verschachtelte Muster machen match mächtig

Übungsaufgabe

Erweitere ausdruck um Division und gib bei Division durch null ein Error zurück.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Listen, Tupel und Records

Weiter: Module, Strings und Standardbibliothek

Alle Kapitel: OCaml im Überblick