123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- (library (alist-helpers)
- (export alist-refs
- alist-set
- alist-item-key
- alist-item-value
- alist-find-item-by-value
- alist-find-item-by-key)
- (import (rnrs base)
- (only (guile)
- lambda* λ
- ;; command line args
- simple-format
- current-output-port)
- ;; GNU Guile batteries
- (ice-9 exceptions)
- ;; SRFIs
- ;; SRFI 1 - list procs
- (srfi srfi-1)
- ;; SRFI 43 - vector procs
- (srfi srfi-43)
- ;; SRFI 69 - hash tables
- (srfi srfi-69))
- (define rest cdr)
- (define alist-item-key
- (λ (item)
- "Get the key of the given ITEM of an alist."
- (first item)))
- (define alist-item-value
- (λ (item)
- "Get the value of the given ITEM of an alist."
- (cdr item)))
- (define alist-find-item-by-value
- (lambda* (val alst #:key (equal-test equal?))
- "Find an item of the given alist ALST by given value VAL
- and return it."
- (find (λ (entry)
- (equal-test (alist-item-value entry) val))
- alst)))
- (define alist-find-item-by-key
- (lambda* (key alst #:key (equal-test equal?))
- "Find an item of the given alist ALST by given key KEY
- and return it."
- (find (λ (entry)
- (equal-test (first entry) key))
- alst)))
- (define alist-refs
- (lambda* (alist refs #:key (default-thunk #f) (equal-test equal?))
- ;; (simple-format (current-output-port) "remaining refs for alist: ~a\n" refs)
- (cond
- ;; If no more refs are given, we must have found what
- ;; we are looking for.
- [(null? refs) alist]
- [(pair? alist)
- (cond
- ;; If there are no more entries in the current alist,
- ;; then we could not find the searched key.
- [(null? alist)
- ;; If a default thunk was given, call it, otherwise
- ;; raise an exception.
- (if default-thunk
- (default-thunk)
- (raise-exception
- (make-exception (make-non-continuable-error)
- (make-exception-with-message "key not found")
- (make-exception-with-irritants (list refs alist))
- (make-exception-with-origin 'alist-refs))))]
- [else
- (let ([ref (first refs)]
- [item (first alist)])
- (cond
- [(equal-test (alist-item-key item) ref)
- (alist-refs (alist-item-value item)
- (drop refs 1)
- #:default-thunk default-thunk
- #:equal-test equal-test)]
- [else
- (alist-refs (drop alist 1)
- refs
- #:default-thunk default-thunk
- #:equal-test equal-test)]))])]
- [else
- ;; (simple-format (current-output-port) "not a pair: ~a\n" alist)
- (if default-thunk
- (default-thunk)
- (raise-exception
- (make-exception (make-non-continuable-error)
- (make-exception-with-message "key not found")
- (make-exception-with-irritants (list refs alist))
- (make-exception-with-origin 'alist-refs))))])))
- (define alist-set
- (lambda* (alst key val #:key (equal-test equal?))
- "Set a given value VAL for a given KEY in the given
- association list ALST."
- (cond
- [(null? alst) (cons (cons key val) '())]
- [else
- (let ([current-assoc (first alst)])
- (cond
- [(equal-test (alist-item-key current-assoc) key)
- (cons (cons key val)
- (drop alst 1))]
- [else
- (cons current-assoc
- (alist-set (drop alst 1)
- key
- val
- #:equal-test equal-test))]))])))
- (define alist?-shallow
- (λ (lst)
- "Check, whether LST is an association list, by only looking
- at the first item."
- (cond
- [(null? lst) #t]
- [(pair? lst)
- (pair? (first lst))]
- [else #f])))
- (define alist-any-key
- (lambda* (alst pred)
- "Check, whether any key in the alist ALST satisfies the
- given predicate PRED."
- (cond
- [(null? alst) #f]
- [else
- (let ([first-key (alist-item-key (first alst))]
- [first-val (alist-item-value (first alst))])
- (cond
- ;; Check the predicate for the first key.
- [(pred first-key) #t]
- ;; If the first value seems to be an association
- ;; list itself, then check it and the rest of the
- ;; alist keys at the current level.
- [(alist?-shallow first-val)
- (or (alist-any-key first-val pred)
- (alist-any-key (drop alst 1) pred))]
- [else
- ;; Check the rest of the keys of the association
- ;; list.
- (alist-any-key (drop alst 1) pred)]))])))
- (define alist-any-value
- (λ (alst pred)
- "Check, whether any value in the alist ALST satisfies the
- given predicate PRED."
- (cond
- [(null? alst) #f]
- [else
- (let ([first-val (alist-item-value (first alst))])
- (cond
- [(pred first-val) #t]
- [(alist?-shallow first-val)
- (or (alist-any-value first-val pred)
- (alist-any-value (drop alst 1) pred))]
- [else
- (alist-any-value (drop alst 1) pred)]))])))
- (define alist-set*
- (lambda* (alst keys val #:key (equal-test equal?))
- "Set value VAL inside the alist ALST navigating through its
- keys using KEYS to get to the place where VAL shall be the
- new value."
- (define traverse
- (λ (alst keys)
- (cond
- [(null? keys) val]
- [(not (alist?-shallow alst))
- (raise-exception
- (make-exception (make-non-continuable-error)
- (make-exception-with-message "key not found")
- (make-exception-with-irritants keys)
- (make-exception-with-origin 'alist-set*)))]
- [(null? alst) (cons (cons (first keys)
- val)
- '())]
- [else
- (let ([current-assoc (first alst)]
- [item-key (alist-item-key (first alst))])
- (cond
- [(equal-test item-key (first keys))
- ;; Change the value and cons the rest of the list.
- (cons (cons item-key
- (traverse (alist-item-value current-assoc)
- (drop keys 1)))
- (drop alst 1))]
- [else
- (cons current-assoc
- (traverse (drop alst 1) keys))]))])))
- (traverse alst keys))))
|