Idiomdrottning’s homepage

call-vector and call-string

The reason to use vectors over lists is when you have a length or structure that’s not gonna change very much. You’re not appending and consing, you’re just setting and getting.

Let’s create a call-vector that has more in common with our call-table from the other day since we already have as-list for all our treating-vectors-as-if-they-were-lists needs.

In other words, we wanna create a great experience on setting and getting particular slots and ranges.

While we’re at it, let’s make call-vectors, call-lists and call-strings all with the same interface.

Creating them

You can create a call-vector, a call-list or a call-string using an existing vector, a list of values, a number (which becomes the length), or a string of characters.

(define foo (call-string "so much for this"))

Then, of course, getting and setting specific slots is straight-forward:

(foo 3)

gets the third slot.

(foo 5 #\a)

sets the fifth slot to the character #\a.

Under the hood access

Just as with call-tables, calling without any arguments gives us the underlying data so we can operate directly on it.

(foo)

⇒ “so muah for this”

And we can use the update: keyword to swap out the underlying vector or string.

(foo update: "so much for this")
(foo)

⇒ “so much for this”

Accessing slices

Using the keyword slice: and two indices you can access every value between them.

(foo slice: 3 7)

⇒ (#\m #\u #\c #\h)

Negative numbers count backwards from the end.

(foo slice: -4 -0)

⇒ (#\t #\h #\i #\s)

Mancala style sowing

You can also easily set several sequential values at once, like in the board game Mancala. Use a start index and the keyword sow:

(foo 3 sow: "this")
(foo -4 sow: #\t #\h #\a #\t)
(foo)

⇒ “so this for that”

Or don’t use a start index and to just sow from the start.

(foo sow: "as")
(foo)

⇒ “as that for this”

Slices are always lists. This is list processing. But that makes the slices perfect for sowing, which can take strings, lists, vectors, or args of single values.

(define example (call-string "kiling"))
(example sow: (reverse (example slice: 0 3)))
(example)

⇒ “liking”

Generalized set!

You can also use set! for specific slots, like this:

(set! (foo 3) #\m)
(foo)

⇒ “as mhat for this”

And you can also use set! to swap out the underlying data, like this:

(set! (foo) "this")
(set! (foo 3) #\m)
(foo)

⇒ “thim”

You can also set! to slices.

(define adage (call-vector #(what the story of this world)))
(set! (adage slice: 2 5) #(flavor of the))

⇒ #(what the flavor of the world)

You can use a couple of different data types:

(set! (adage slice: 2 5) "abc")

⇒ #(what the #\a #\b #\c world)

(set! (adage slice: 2 5) 456)

⇒ #(what the 4 5 6 world)

(set! (adage slice: 2 5) (iota 3))

⇒ #(what the 0 1 2 world)

Using call-string and call-vector anonymously

The seeding makes it convenient to use these on any string or vector for a one-shot use.

(define str "My ordinary string defined outside.")
((call-string str) sow: "An")
str

⇒ “An ordinary string defined outside.”

((call-string str) 4)

⇒ #\r

Bringing call-table up to speed

call-string and call-vector are part of brev-separate version 1.6. Negative indices (outside of slices, where they were already supported) were introduced in version 1.8.

Starting from that version, call-table now also supports seeding with a value (must be an alist or a hash-table), using the keyword seed:, but unlike with call-string and call-vector, this is optional and call-tables can start out empty.

call-table now also supports set!, both for slots and for the underlying hash-table as a whole.

For source code,

git clone https://idiomdrottning.org/brev-separate