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. 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
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) => #trecord-vector?
(record-vector? VAR)Unstrict predicate which test structure of argument VAR is like Scheme pair of list and vector.
record-vector-clone
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? 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? symmetricalrecord-vector-attr?
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
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!
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!
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