EMZETT.
Login

Kurz: Seq beschreibt unendliche oder träge Folgen, die erst bei Bedarf berechnet werden:

Teil des Kurses OCaml

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

Faltungen und Funktionen höherer Ordnung

let () =
  let l = [3; 1; 4; 1; 5; 9; 2; 6] in
  let summe = List.fold_left (+) 0 l in
  let produkt = List.fold_left ( * ) 1 l in
  let maximum = List.fold_left max min_int l in
  Printf.printf "%d %d %d\n" summe produkt maximum;
  (* eigene fold_right: baut die Liste von rechts auf *)
  let kopie = List.fold_right (fun x acc -> x :: acc) l [] in
  Printf.printf "%b\n" (kopie = l);
  let haeufigkeit =
    List.fold_left (fun acc x ->
      let n = try List.assoc x acc with Not_found -> 0 in
      (x, n + 1) :: List.remove_assoc x acc) [] l in
  List.iter (fun (k, n) -> Printf.printf "%d:%d " k n) (List.sort compare haeufigkeit);
  print_newline ();
  Printf.printf "%s\n" (String.concat "," (List.map string_of_int (List.sort_uniq compare l)))

Ausgabe:

31 6480 9
true
1:2 2:1 3:1 4:1 5:1 6:1 9:1
1,2,3,4,5,6,9

Lazy und Sequenzen

Seq beschreibt unendliche oder träge Folgen, die erst bei Bedarf berechnet werden:

let rec nat_ab n () = Seq.Cons (n, nat_ab (n + 1))
 
let () =
  let erste = nat_ab 1 |> Seq.map (fun x -> x * x) |> Seq.filter (fun x -> x mod 3 = 0) |> Seq.take 4 in
  Seq.iter (Printf.printf "%d ") erste;
  print_newline ();
  let l = lazy (print_endline "berechne"; 42) in
  print_endline "vorher";
  Printf.printf "%d\n" (Lazy.force l);
  Printf.printf "%d\n" (Lazy.force l);
  let s = Seq.init 5 (fun i -> i * 2) in
  Printf.printf "%d\n" (Seq.fold_left (+) 0 s)

Ausgabe:

9 36 81 144
vorher
berechne
42
42
20

Polymorphe Varianten und GADTs

Polymorphe Varianten (`Name) brauchen keine Typdeklaration. GADTs verfeinern Typen je Konstruktor:

let beschreibe = function
  | `Rot -> "rot"
  | `Gruen -> "grün"
  | `Rgb (r, g, b) -> Printf.sprintf "rgb(%d,%d,%d)" r g b
 
type _ ausdruck =
  | Int : int -> int ausdruck
  | Bool : bool -> bool ausdruck
  | Plus : int ausdruck * int ausdruck -> int ausdruck
  | Ist_null : int ausdruck -> bool ausdruck
  | Wenn : bool ausdruck * 'a ausdruck * 'a ausdruck -> 'a ausdruck
 
let rec eval : type a. a ausdruck -> a = function
  | Int n -> n
  | Bool b -> b
  | Plus (a, b) -> eval a + eval b
  | Ist_null a -> eval a = 0
  | Wenn (c, a, b) -> if eval c then eval a else eval b
 
let () =
  print_endline (beschreibe `Rot);
  print_endline (beschreibe (`Rgb (1, 2, 3)));
  Printf.printf "%d\n" (eval (Wenn (Ist_null (Int 0), Plus (Int 1, Int 2), Int 0)));
  Printf.printf "%b\n" (eval (Ist_null (Plus (Int 1, Int 1))))

Ausgabe:

rot
rgb(1,2,3)
3
false

Ein Plus (Bool true, Int 1) wird vom Compiler abgelehnt: Der Typ des Ausdrucks steckt im Typ.

Funktoren

Ein Funktor ist ein Modul, das aus einem Modul ein neues erzeugt:

module type VERGLEICH = sig
  type t
  val vergleiche : t -> t -> int
end
 
module Sortierer (V : VERGLEICH) = struct
  let sortiere l = List.sort V.vergleiche l
  let maximum = function [] -> None | x :: r -> Some (List.fold_left (fun a b -> if V.vergleiche a b >= 0 then a else b) x r)
end
 
module Absteigend = Sortierer (struct
  type t = int
  let vergleiche a b = compare b a
end)
 
module NachLaenge = Sortierer (struct
  type t = string
  let vergleiche a b = compare (String.length a) (String.length b)
end)
 
let () =
  List.iter (Printf.printf "%d ") (Absteigend.sortiere [3; 9; 1; 7]);
  print_newline ();
  List.iter (Printf.printf "%s ") (NachLaenge.sortiere ["ccc"; "a"; "bb"]);
  print_newline ();
  match NachLaenge.maximum ["x"; "yyyy"; "zz"] with Some s -> print_endline s | None -> ()

Ausgabe:

9 7 3 1
a bb ccc
yyyy

Objekte

OCaml hat auch ein Objektsystem (selten genutzt):

class zaehler (start : int) = object
  val mutable n = start
  method erhoehe = n <- n + 1
  method wert = n
end
 
let () =
  let z = new zaehler 10 in
  z#erhoehe; z#erhoehe;
  Printf.printf "%d\n" z#wert;
  let punkt = object
    method x = 3
    method y = 4
    method abstand = sqrt (float_of_int (3 * 3 + 4 * 4))
  end in
  Printf.printf "%.1f\n" punkt#abstand

Ausgabe:

12
5.0

Merke

  • fold_left/fold_right sind die Grundlage vieler Listenoperationen
  • Seq und lazy verzögern Berechnungen
  • Polymorphe Varianten (`A) und GADTs bieten feinere Typen
  • Funktoren erzeugen Module aus Modulen; Objekte gibt es, werden aber selten benutzt

Übungsaufgabe

Schreibe einen Funktor Zaehler(S), der für beliebige Vergleichsmodule Häufigkeiten zählt.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Module, Strings und Standardbibliothek

Weiter: Dateien, Werkzeuge und Ökosystem

Alle Kapitel: OCaml im Überblick