Kurz: (define (anwenden f x) (f x)) (define (zweimal f) (lambda (x) (f (f x)))) (define (kompose . fs) (if (null? fs) identity (lambda (x) ((car fs) ((apply kompose (cdr fs)) x))))) (define (addierer n) (lambda (x) (+ x n)))
Teil des Kurses Racket
Funktionen als Werte
#lang racket
(define (anwenden f x) (f x))
(define (zweimal f) (lambda (x) (f (f x))))
(define (kompose . fs)
(if (null? fs) identity (lambda (x) ((car fs) ((apply kompose (cdr fs)) x)))))
(define (addierer n) (lambda (x) (+ x n)))
(displayln (anwenden add1 5))
(displayln ((zweimal add1) 5))
(displayln ((kompose add1 (lambda (x) (* x 10))) 4))
(displayln (map (addierer 100) '(1 2 3)))
(displayln ((curry + 5) 10))
(displayln ((curryr - 1) 10))
(displayln ((compose add1 sqr) 5))
(displayln (map + '(1 2 3) '(10 20 30)))
(displayln (apply map list '((1 2 3) (4 5 6))))
(displayln (sort '("ccc" "a" "bb") < #:key string-length))
(displayln (foldr cons '() '(1 2 3)))
(displayln (foldl cons '() '(1 2 3)))
(displayln (filter-not even? '(1 2 3 4)))
(displayln (let loop ([n 5] [acc '()]) (if (zero? n) acc (loop (sub1 n) (cons n acc)))))Ausgabe:
6
7
41
(101 102 103)
15
9
26
(11 22 33)
((1 4) (2 5) (3 6))
(a bb ccc)
(1 2 3)
(3 2 1)
(1 3)
(1 2 3 4 5)Closures und Zustand
#lang racket
(define (make-zaehler)
(define n 0)
(lambda () (set! n (add1 n)) n))
(define a (make-zaehler))
(define b (make-zaehler))
(a) (a)
(displayln (list (a) (b)))
(define (memoize f)
(define cache (make-hash))
(lambda args
(hash-ref! cache args (lambda () (apply f args)))))
(define langsam-fib
(lambda (n) (if (< n 2) n (+ (langsam-fib (- n 1)) (langsam-fib (- n 2))))))
(set! langsam-fib (memoize langsam-fib))
(displayln (langsam-fib 80))
(define-values (get set) (let ([x 0]) (values (lambda () x) (lambda (v) (set! x v)))))
(set 42)
(displayln (get))Ausgabe:
1
2
(3 1)
23416728348467685
42Makros
define-syntax-rule erzeugt einfache Syntaxerweiterungen:
#lang racket
(define-syntax-rule (wiederhole n rumpf ...)
(for ([i n]) rumpf ...))
(define-syntax-rule (tausche! a b)
(let ([tmp a]) (set! a b) (set! b tmp)))
(define-syntax-rule (mein-unless bedingung rumpf ...)
(if bedingung (void) (begin rumpf ...)))
(define-syntax-rule (zeit-block name rumpf ...)
(begin (printf "Start ~a~n" name) (begin0 (let () rumpf ...) (printf "Ende ~a~n" name))))
(wiederhole 3 (display "x "))
(newline)
(define p 1)
(define q 2)
(tausche! p q)
(displayln (list p q))
(mein-unless #f (displayln "läuft"))
(displayln (zeit-block "Rechnung" (+ 40 2)))
(define-syntax for-each-paar
(syntax-rules ()
[(_ ((x y) liste) rumpf ...)
(for-each (lambda (paar) (let ([x (car paar)] [y (cdr paar)]) rumpf ...)) liste)]))
(for-each-paar ((k v) '((a . 1) (b . 2))) (printf "~a=~a " k v))
(newline)Ausgabe:
x x x
(2 1)
läuft
Start Rechnung
Ende Rechnung
42
a=1 b=2Tipp
Racket-Makros sind hygienisch: Hilfsvariablen wie
tmpkollidieren nicht mit Namen des Aufrufers.
Fehler und Verträge
#lang racket
(define (teile a b)
(when (zero? b) (raise-user-error 'teile "Division durch null"))
(/ a b))
(with-handlers ([exn:fail? (lambda (e) (displayln (string-append "Fehler: " (exn-message e))))])
(teile 1 0))
(with-handlers ([exn:fail:contract:divide-by-zero? (lambda (e) (displayln "durch null"))])
(/ 1 0))
(with-handlers ([string? (lambda (s) (displayln (string-append "String geworfen: " s)))])
(raise "etwas ist schiefgelaufen"))
(define/contract (quadrat x)
(-> number? number?)
(* x x))
(displayln (quadrat 6))
(with-handlers ([exn:fail:contract? (lambda (e) (displayln "Vertrag verletzt"))])
(quadrat "x"))
(dynamic-wind
(lambda () (displayln "vorher"))
(lambda () (displayln "mittendrin"))
(lambda () (displayln "nachher")))
(displayln (call-with-current-continuation (lambda (k) (+ 1 (k 42)))))Ausgabe:
Fehler: teile: Division durch null
durch null
String geworfen: etwas ist schiefgelaufen
36
Vertrag verletzt
vorher
mittendrin
nachher
42Merke
- Funktionen sind Werte:
lambda,curry,compose,map,foldl - Closures kapseln Zustand mit
set!; Memoization per Hashtabelle define-syntax-ruleundsyntax-ruleserzeugen hygienische Makroswith-handlers,raise,define/contractunddynamic-windbehandeln Fehler
Übungsaufgabe
Schreibe ein Makro my-while, das eine Bedingung wiederholt prüft.
Quiz zur Selbstkontrolle
Was bedeutet "hygienisches Makro"?
- Hilfsvariablen kollidieren nicht mit Namen des Aufrufers (richtig)
- Das Makro ist besonders sauber formatiert
- Es ist schneller
- Es hat keine Argumente
Was erzeugt define-syntax-rule?
- Ein einfaches Makro (richtig)
- Eine Funktion
- Eine Klasse
- Ein Modul
Wie fängt man Fehler ab?
- with-handlers (richtig)
- try/catch
- rescue
- on-error
Weiter im Kurs
Zurück: Strings, Vektoren, Hashtabellen und Strukturen
Weiter: Klassen, Module und Typen
Alle Kapitel: Racket im Überblick