record-vector
Description
Record-vector is a module for CHICKEN5|6 Scheme, and R7RS library for #:Guile :Gauche Gambit: Schemes, designed to work with key-value data structures, aka records. Record-vector does not declare a new record type, it is not a hash-table, nor a tree. Record-vector itself is just a pair of alist of attribute indexes in the second part of pair - value's vector.
'(((#:KW1 . INDEX1) ... (#:KWN . INDEXN)) . #(VALUE1 ... VALUEN))
KW - name of attribute, also Scheme keyword #:NAME or NAME: depend of Scheme variant. VALUE - any Scheme value.
Cons
- Access to the record attribute barely dumb sequence of number? + car + assq + vector-ref
- Record-vectors are not tagtyped but duck typed
- It's not bit-compact
- Nor cache frendly it is user frendly records.
Pros
- Transparent good old way of the Lisp data representation (sic!)
- automatic serialization by read/write
- easy handy creation
- automatic data import (in memory of SRFI-9 import-export access proc.s hell)
- Access to the attribute value by the #:keyword or by index
- Access to the attribute of record-vector inside record-vector, recursive, by path of keywords or indexes.
Example. Basic usage
> (record-vector #:x 0.0 #:speed 0.1) => (((#:x . 0) (#:speed . 1)) . #(0.0 0.1)) ;; make-rv an alias of [procedure]record-vector > (define boat (make-rv #:posn (make-rv #:x 1.0 #:y 2.0) #:id 10001 #:passengers 4)) ;; record-vector-ref/rv-ref is accessor procedure/macro (last one supports inner rv chain access) > (rv-ref boat #:posn #:y) => 2.0 ;; same reference by attribute indexes > (rv-ref boat 0 1) => 2.0 ;; Zero - #:posn, 1 - #:y in position. ;; the record-vector extends in this way > (rv-attr? boat #:model) => #f > (rv-update! boat #:model "Azimut 50") > (rv-attr? boat #:model) => (#:model . 3) ;; get attribute by index > (rv-ref boat 3) => "Azimut 50"
Example. Compound record-vector
(define objects (record-vector #:table (make-rv #:posn (make-rv #:x 100 #:y 20) #:height 80 #:items (make-rv #:cup (make-rv #:posn (make-rv #:x 10 #:y 0)) #:pot (make-rv #:posn (make-rv #:x 20 #:y 10)))))) > (cdr (rv-ref objects #:table #:items #:pot #:posn)) => #(20 10)
Requirements
Non standard predicate keyword? and utility (R7RS) procedure vector-append are used (in CHICKEN5 it's used from vector-lib package). Also in CHICKEN SRFI-17 setter adapter used for record-vector-ref.
API
All record-vector-* forms has rv-* shortcomings, some in form of macros with extended abilities.
record-vector
[procedure] (record-vector [#:NAME-1 VALUE-1 ... #:NAME-N VALUE-N])[procedure] (make-rv [#:NAME-1 VALUE-1 ... #:NAME-N VALUE-N])
Record-vector construction procedures. make-rv is an alias of record-vector
- NAME-1 - first attribute name - scheme keyword #:NAME (or NAME: in CHICKEN)
- VALUE-1 - first attribute value
record-vector may be empty.
> (record-vector #:code "defs.scm" #:lang 'Scheme #:loc 117)) => (((#:code . 0) (#:lang . 1) (#:loc . 2)) . #("defs.scm" Scheme 117)) > (define empty-obj (make-rv)) > empty-obj => (() . #()) > (record-vector? empty-obj) => #t
record-vector?
[procedure] (record-vector? VAR)Unstrict predicate which test structure of argument VAR is like Scheme pair of list and vector.
record-vector-clone
[procedure] (record-vector-clone R-V-SRC [#:NAME-k #:NEW-VALUE-k ...])[procedure] (rv-clone R-V-SRC [#:NAME-k #:NEW-VALUE-k ...])
Create the new record-vector by consing attributes alist of R-V-SRC and copy of R-V-SRC value vector. If every n-th value also record-vector? than recursive clone it inplace of new n-th value. Also apply new values to existing attributes with name #:NAME-k or extends new record-vector with them.
> (define r (record-vector #:x 1.0 #:y 3.0)) > (define r2 (record-vector-clone r #:y 2.0 #:z 3.0)) > r2 => (((#:x . 0) (#:y . 1) (#:z . 2)) . #(1.0 2.0 3.0))
record-vector-like?
[procedure] (record-vector-like? r1 r2)[procedure] (rv-like? r1 r2)
Procedure record-vector-like? returns true if all of attribute names in r1.alist also in r2.alist or vice versa.
> (define r1 (make-rv x: 1 y: 2 z: 3)) > (define r2 (make-rv x: 4 y: 2)) > (rv-like? r1 r2) => #t ;; bc all attributes from r2 are present in r1. > (rv-like? r2 r1) => #t ;; still True, record-vector-like? symmetrical
record-vector-attr?
[procedure] (record-vector-attr? R-V #:NAME)[procedure] (rv-attr? R-V #:NAME)
This proc's for check presence of the attribute #:NAME in alist dictionary of R-V. Returns (assq #:NAME r-v.alist).
record-vector-ref
[procedure] (record-vector-ref R-V #:NAME-k #!optional DEFAULT)[syntax] (rv-ref R-V #:NAME-k [#:SUB-NAME-j ...])
This is accesor of the attribute of the record-vector R-V. In CHICKEN record-vector-ref (not the rv-ref) SRFI-17 compatible. Optional DEFAULT value is used if there is no attribute named #:NAME-k.
The rv-ref macro works like record-vector-ref, but if the value with #:NAME-k is a record-vector?, it looks for the value of the #:SUB-NAME-j attribute in it, recursively. The macro does not have a default return value, unlike record-vector-ref.
> (record-vector-ref (record-vector #:x 124 #:y 0) #:x) => 124 > (record-vector-ref (make-rv #:x 1) #:t 1900) => 1900 > ;; but no default value in rv-ref macro > (rv-ref (make-rv #:x 1) #:t 1990) => Error: (cdr) bad argument type: #f > (rv-ref (make-rv #:person (make-rv #:name "Joe" #:age 50)) #:person #:name ) => "Joe" ;; if attribute is not present it returns False (use rv-attr? predicate before) > (rv-ref (make-rv #:posn (make-rv #:x 0.0 #:y 0.0)) #:posn #:z) => #f ....
record-vector-set!
[procedure] (record-vector-set! R-V #:NAME-k NEW-VALUE)[syntax] (rv-set! R-V #:NAME-k [#:SUB-R-V-NAME-j ...] NEW-VALUE)
record-vector-set! is a mutator of the record-vector attribute NAME rv-set! - recursive macro which able set value not only R-V but attributes compatible with record-vector structure
> (define r (record-vector #:pos 0.0 #:line (make-rv #:color 'red #:a 1.0 #:b 2))) > r => (((#:pos . 0) (#:line . 1)) . #(0.0 (((#:color . 0) (#:a . 1) (#:b . 2)) . #(red 1.0 2)))) > (set! (record-vector-ref r #:pos) 1000.0) ;; SRFI-17 > r => (((#:pos . 0) (#:line . 1)) . #(1000.0 (((#:color . 0) (#:a . 1) (#:b . 2)) . #(red 1.0 2)))) > (rv-set! r #:line #:color 'blue) > r => (((#:pos . 0) (#:line . 1)) . #(1000.0 (((#:color . 0) (#:a . 1) (#:b . 2)) . #(blue 1.0 2))))
record-vector-update!
[procedure] (record-vector-update! R-V #:NAME VALUE)[syntax] (rv-update! R-V #:NAME [#:SUB-NAME ...] VALUE)
These procedure and macro (which recursive variant) for update existing attribute values and add new attribute in record-vector R-V.
> (define p (make-rv posn: (make-rv x: 1 y: 2))) > (rv-update! p posn: x: 10) > p => (((#:posn . 0)) . #((((#:x . 0) (#:y . 1)) . #(10 2)))) > (rv-update! p posn: z: 30) > p => (((#:posn . 0)) . #((((#:x . 0) (#:y . 1) (#:z . 2)) . #(10 2 30)))) ;; rv-update! is stable > (rv-update! p posn: z: 30) > p => (((#:posn . 0)) . #((((#:x . 0) (#:y . 1) (#:z . 2)) . #(10 2 30))))
Example
(import (rename (record-vector) (record-vector rv))) (let ((r (rv x: 1 y: 2)) (nr (rv x: 2 y: 3))) (define (distance p t) (let ((dx (- (rv-ref t #:x) (rv-ref p #:x))) (dy (- (rv-ref t #:y) (rv-ref p #:y)))) (sqrt (+ (* dx dx) (* dy dy))))) (= (distance r nr) (distance nr r)))
Source code
Authors
Licence
BSD-2-Clause licence.
Version History
- 1.0.1 Fixed/simplified dependencies list in .egg
- 1.0.0 Initial release