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)))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)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))))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 -> ()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#abstand12 5.0
Merke
fold_left/fold_rightsind die Grundlage vieler ListenoperationenSequndlazyverzögern Berechnungen- Polymorphe Varianten (`
A ``) und GADTs bieten feinere Typen - Funktoren erzeugen Module aus Modulen; Objekte gibt es, werden aber selten benutzt
Aufgabe
Schreibe einen Funktor Zaehler(S), der für beliebige Vergleichsmodule Häufigkeiten zählt.