Magic Dict
Tuesday, November 21, 2023
The Raku programming language community comes up with interesting modules, and I enjoy getting emails from the Rakudo Weekly News. This week, there was a link to a post from a few days ago about making a weird data structure in Raku:
I came up with a weird data structure. It’s a hash, but you can also add functions that receive the hash as input so you can do math with it (if you squint, it’s vaguely like a spreadsheet). Something like:
m = MagicDict() m["a"] = 1 m["b"] = 2 m["sum"] = lambda self: self["a"] + self["b"] print(m["sum"])
Ideally, I’d want to do this in #RakuLang. (I know it’s possible because I did something much weirder once (I gave Str a CALL-ME method).)
I thought it would be fun to build this in Factor –
starting with a magic-dict
class that:
- wraps an assoc which we will use to store all of the items
- has a constructor using a hashtable by default
- marked as an instance of assoc, so we support generic words defined on assocs
- support the assoc protocol using the delegate vocabulary to defer to the wrapped assoc
TUPLE: magic-dict assoc ;
: <magic-dict> ( -- magic-dict ) H{ } clone magic-dict boa ;
INSTANCE: magic-dict assoc
CONSULT: assoc-protocol magic-dict assoc>> ;
And the main piece of logic we need is to implement the at*
lookup word
and, if the value is a
callable,
call it with the assoc on the stack as an argument.
M: magic-dict at*
swap over assoc>> at* over callable?
[ drop call( assoc -- value ) t ] [ nipd ] if ;
This allows us to make a Factor version of the original example:
IN: scratchpad <magic-dict>
1 "a" pick set-at
2 "b" pick set-at
[ [ "a" of ] [ "b" of ] bi + ] "sum" pick set-at
IN: scratchpad "sum" of .
3
Pretty cool!