Idiomdrottning’s homepage

ref*

Ref* is a universal version of list-ref, hash-table-ref etc.

It can handle lists, alists, hash-tables, strings, vectors, records, and all callable procedures (like call-tables).

You can also pass multiple arguments to dereference recursively.

The order is left to right, like Java’s dots or Clojure’s arrow, unlike compose or nested calls. That is to say, the left-most is the outermost.

Here’s an extended example.

(define foo (make-hash-table))
(set! (ref* foo 'bar) '((x . #(1 2 3)) (y . #(4 5 6))))

(ref* foo 'bar)
⇒ ((x . #(1 2 3)) (y . #(4 5 6)))

(ref* foo 'bar 'y)
⇒ #(4 5 6)

(ref* foo 'bar 'y 0)
⇒ 4

(set!  (ref* foo 'bar 'y 0) 5)

(ref* foo 'bar 'y 0)
⇒ 5

There’s also the refx variant which creates dereferencers:

((refx 'bar 'y 0) foo)
⇒ 5

For example, you could make a car that worked on strings and vectors too, like this: (refx 0) and you could make a caddar like this: (refx 2 0).

Chris asked me yesterday:

Did you ever do anything more with ref? (To jog your memory, the magic operator for traversing nested structures).

He designed it last spring and posted it to the brev-dev mailing list.

I dug up the old thread and added it to brev-separate, starting with version 1.80.

I think there are three reasons I forgot about it. Unlike clojure where you need to dereference deep objects all the time, here I usually use either callable structures (which already compose), or it’s all lists and I can use sxpath or caddar, or I use the destructuring power of the fanciest define of all time.

So we made sure that ref* plays nicely with all of that! It can handle callables and alists just fine, and the fanciest define of all time can also use them:

(define (example foo (= (refx 3 ->string 2) bar))
  (string foo bar))

(example #\h '(I wonder what this is))
⇒ "hi"

Ref* is sort of related to the -> notation brev reexports from the clojurian egg; it trades away being able to use arbitrary paren expressions for being able to use any index or key (along with unary transformators).

Update:

Wasamasa pointed out that SRFI-123 exists so I renamed the procedures to be a li’l bit closer. This post now reflects the new names.