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.
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
.
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”
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)
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”
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)
call-string
and call-vector
anonymouslyThe 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
call-table
up to speedcall-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