Guile bindings

This library includes experimental bindings that provide efficient immutable vectors for the GNU Guile Scheme implementation. The interface is somewhat incomplete, but you can already do something interesting things like:

(use-modules (immer)
             (rnrs base))

(let ((v1 (ivector 1 "hola" 3 'que #:tal)))
  (assert (eq? (ivector-ref v1 3) 'que))

  (let* ((v2 (ivector-set v1 3 'what))
         (v2 (ivector-update v2 2 (lambda (x) (+ 1 x)))))
    (assert (eq? (ivector-ref v1 2) 3))
    (assert (eq? (ivector-ref v1 3) 'que))
    (assert (eq? (ivector-ref v2 2) 4))
    (assert (eq? (ivector-ref v2 3) 'what))

    (let ((v3 (ivector-push v2 "hehe")))
      (assert (eq? (ivector-length v3) 6))
      (assert (eq? (ivector-ref v3 (- (ivector-length v3) 1)) "hehe")))))

(let ((v (apply ivector (iota 10))))
  (assert (eq? (ivector-length v) 10))
  (assert (eq? (ivector-length (ivector-drop v 3)) 7))
  (assert (eq? (ivector-length (ivector-take v 3)) 3))
  (assert (eq? (ivector-length (ivector-append v v)) 20)))

(let ((v1 (make-ivector 3))
      (v2 (make-ivector 3 ":)")))
  (assert (eq? (ivector-ref v1 2)
               (vector-ref (make-vector 3) 2)))
  (assert (eq? (ivector-ref v2 2) ":)")))
Do you want to help making these bindings complete and production ready? Drop a line at immer@sinusoid.al or open an issue on GitHub

Installation

To install the software, you need GNU Guile 2.2. Then you have to clone the repository and inside the repository do something like:

mkdir build; cd build
cmake .. -DCMAKE_BUILD_TYPE=Release \
         -DGUILE_EXTENSION_DIR="<somewhere...>"
make guile
cp extra/guile/libguile-immer.so "<...the GUILE_EXTENSION_DIR>"
cp extra/guile/immer.scm "<somewhere in your GUILE_LOAD_PATH>"

Benchmarks

The library includes some quick and dirty benchmarks that show how these vectors perform compared to mutable vectors, lists, and v-lists. Once you have installed the library, you may run them by executing the following in the project root:

guile extra/guile/benchmark.scm

This is the output I get when running those:

(define bench-size 1000000)
(define bench-samples 10)
;;;; benchmarking creation...
; evaluating:
      (apply ivector (iota bench-size))
; average time: 0.0608697784 seconds
; evaluating:
      (apply ivector-u32 (iota bench-size))
; average time: 0.0567354933 seconds
; evaluating:
      (iota bench-size)
; average time: 0.032995402 seconds
; evaluating:
      (apply vector (iota bench-size))
; average time: 0.0513594425 seconds
; evaluating:
      (apply u32vector (iota bench-size))
; average time: 0.0939185315 seconds
; evaluating:
      (list->vlist (iota bench-size))
; average time: 0.2369570977 seconds
;;;; benchmarking iteration...
(define bench-ivector (apply ivector (iota bench-size)))
(define bench-ivector-u32 (apply ivector-u32 (iota bench-size)))
(define bench-list (iota bench-size))
(define bench-vector (apply vector (iota bench-size)))
(define bench-u32vector (apply u32vector (iota bench-size)))
(define bench-vlist (list->vlist (iota bench-size)))
; evaluating:
      (ivector-fold + 0 bench-ivector)
; average time: 0.035750341 seconds
; evaluating:
      (ivector-u32-fold + 0 bench-ivector-u32)
; average time: 0.0363843682 seconds
; evaluating:
      (fold + 0 bench-list)
; average time: 0.0271881423 seconds
; evaluating:
      (vector-fold + 0 bench-vector)
; average time: 0.0405022349 seconds
; evaluating:
      (vlist-fold + 0 bench-vlist)
; average time: 0.0424709098 seconds
;;;; benchmarking iteration by index...
; evaluating:
      (let iter ((i 0) (acc 0))
        (if (< i (ivector-length bench-ivector))
          (iter (+ i 1) (+ acc (ivector-ref bench-ivector i)))
          acc))
; average time: 0.2195658936 seconds
; evaluating:
      (let iter ((i 0) (acc 0))
        (if (< i (ivector-u32-length bench-ivector-u32))
          (iter (+ i 1) (+ acc (ivector-u32-ref bench-ivector-u32 i)))
          acc))
; average time: 0.2205486326 seconds
; evaluating:
      (let iter ((i 0) (acc 0))
        (if (< i (vector-length bench-vector))
          (iter (+ i 1) (+ acc (vector-ref bench-vector i)))
          acc))
; average time: 0.0097157637 seconds
; evaluating:
      (let iter ((i 0) (acc 0))
        (if (< i (u32vector-length bench-u32vector))
          (iter (+ i 1) (+ acc (u32vector-ref bench-u32vector i)))
          acc))
; average time: 0.0733736008 seconds
; evaluating:
      (let iter ((i 0) (acc 0))
        (if (< i (vlist-length bench-vlist))
          (iter (+ i 1) (+ acc (vlist-ref bench-vlist i)))
          acc))
; average time: 0.3220357243 seconds
;;;; benchmarking concatenation...
; evaluating:
      (ivector-append bench-ivector bench-ivector)
; average time: 1.63022e-5 seconds
; evaluating:
      (ivector-u32-append bench-ivector-u32 bench-ivector-u32)
; average time: 1.63754e-5 seconds
; evaluating:
      (append bench-list bench-list)
; average time: 0.0135592963 seconds
; evaluating:
      (vector-append bench-vector bench-vector)
; average time: 0.0044506586 seconds
; evaluating:
      (vlist-append bench-vlist bench-vlist)
; average time: 0.3227312512 seconds