LilyPond erweitern: 1.1.4 Zusammengesetzte Scheme-Datentypen

### 1.1.4 Zusammengesetzte Scheme-Datentypen

Es gibt auch zusammengesetzte Datentypen in Scheme. Die Datentypen, die in LilyPond häufig benutzt werden, beinhalten Paare, Listen, assoziative Listen und Hash-Tabellen.

### Paare (pair)

Der wichtigeste zusammengesetzte Datentyp in Scheme ist ein Paar (`pair`). Wie aus dem Namen schon hervorgeht, besteht ein Paar aus zwei zusammengeschweißten Werten. Die Prozedur um ein Paar zu erstellen ist `cons`.

    guile> (cons 4 5)
    (4 . 5)
    guile>

Das Paar wird dargestellt als zwei Elemente, von Klammern umgeben und durch Leerzeichen und einen Punkt (`.`) getrennt. Der Punkt ist kein Dezimalpunkt, sondern markiert die Gruppe als Paar.

Paare können auch wörtlich eingegeben werden, indem man ihnen voraus ein einfaches Anführungszeichen (`'` setzt.

    guile> '(4 . 5)
    (4 . 5)
    guile>

Beide Elemente eines Paares können beliebige gültige Scheme-Werte sein:

    guile> (cons #t #f)
    (#t . #f)
    guile> '("blah-blah" . 3.1415926535)
    ("blah-blah" . 3.1415926535)
    guile>

Das erste Element eines Paares kann mit der Prozedur `car`, das zweite mit der Prozedur `cdr` angesprochen werden.

    guile> (define mypair (cons 123 "hello there")
    ... )
    guile> (car mypair)
    123
    guile> (cdr mypair)
    "hello there"
    guile>

Achtung: `cdr` wird ausgeprochen wie "kudd-err", nach Sussman und Abelson, siehe http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-14.html#footnote_Temp_133

### Listen (list)

Ein sehr häufiger Datentyp in Scheme ist die Liste (list). Formal gesehen wird eine Liste entweder als leere Liste definiert (repräsentiert als `'()`), oder als ein Paar, dessen `cdr` eine Liste ist.

Es gibt viele Arten, Listen zu erstellen. Die vielleicht häufigste Methode ist die `list`-Prozedur:

    guile> (list 1 2 3 "abc" 17.5)
    (1 2 3 "abc" 17.5)

Wie man sehen kann, wird eine Liste dargestellt in Form der einzelnen Elemente, getrennt durch ein Leerzeichen und als Gruppe in Klammern eingeschlossen. Anders als bei einem Paar, befindet sich kein Punkt zwischen den Elementen.

Eine Liste kann auch als wörtliche Liste notiert werden, indem man die enthaltenen Elemente in Klammern einschließt und ein einfaches Anführungszeichen voranschreibt:

    guile> '(17 23 "foo" "bar" "bazzle")
    (17 23 "foo" "bar" "bazzle")

Listen haben eine zentrale Stellung in Scheme. Scheme wird als Dialekt von Lisp angesehen, und das Wort „lisp“ steht für „List Processing“. Scheme-Ausdrücke sind immer Listen.

### Assoziative Listen (alist)

Eine besonderer Listentyp ist die assoziative Liste oder alist. Eine Alist wird benutzt, um Daten zum einfachen Abrufen zu speichern.

Alisten sind Listen, deren Elemente als Paare kommen. Der `car`-Teil jedes Elements wird als Schlüssel (key) bezeichnet, der `cdr`-Teil jedes Elements wird Wert (value) genannt. Die Scheme-Prozedur `assoc` wird benutzt, um einen Eintrag aus einer Aliste aufzurufen, und mit `cdr` wird sein Wert abgefragt:

    guile> (define my-alist '((1  . "A") (2 . "B") (3 . "C")))
    guile> my-alist
    ((1 . "A") (2 . "B") (3 . "C"))
    guile> (assoc 2 my-alist)
    (2 . "B")
    guile> (cdr (assoc 2 my-alist))
    "B"
    guile>

Alisten werden sehr viel in LilyPond genutzt, um Eigenschaften und andere Daten zu speichern.

### Hash-Tabellen (hash table)

Eine Datenstruktur, die ab und zu in LilyPond eingesetzt wird. Eine Hash-Tabelle ähnelt einem Array, aber die Indexe des Arrays können beliebige Scheme-Werte sein, nicht nur Integre.

Hash-Tabellen sind effizienter als Alisten, wenn man viele Daten speichern will und die Daten sich oft ändern.

Die Syntax, mit der Hash-Tabellen erstellt werden, ist etwas komplex, aber man kann Beispiele hierzu im LilyPond-Quellcode finden.

    guile> (define h (make-hash-table 10))
    guile> h
    #<hash-table 0/31>
    guile> (hashq-set! h 'key1 "val1")
    "val1"
    guile> (hashq-set! h 'key2 "val2")
    "val2"
    guile> (hashq-set! h 3 "val3")
    "val3"

Werte werden aus den Hash-Tabellen mit `hashq-ref` ausgelesen.

    guile> (hashq-ref h 3)
    "val3"
    guile> (hashq-ref h 'key2)
    "val2"
    guile>

Schlüssel und Werte werden als Paar mit `hashq-get-handle` ausgelesen. Das ist die beste Art, weil hier `#f` ausgegeben wird, wenn ein Schlüssel nicht gefunden werden kann.

    guile> (hashq-get-handle h 'key1)
    (key1 . "val1")
    guile> (hashq-get-handle h 'frob)
    #f
    guile>

#### LilyPond – Extending v2.22.2 (stabiler Zweig).