Term Unpacking and Packing
Xlerb, and other such languages’ biggest strength - that it’s just pushing and popping stuff off the stack - is, in the context of a BEAM language, something of a weakness.
Imagine you’re calling an Elixir function like Date.utc_today/1 and wanting to get at the current year.
In Elixir we’d just call .year on the resulting date struct, or pattern match it out, but in Xlerb we don’t have that luxury.
Enter pack and unpack, our tool for manipulating and massaging Elixir/Erlang terms.
Unpack
Consider calling a function, and then getting back the classic result tuple, {:ok, value}. Let’s say we want to get the current user from the env (without crashing!):
xlerb[0]> [ System get_env 0 ] elixir "USER" [ Map fetch 2 ] elixir
xlerb[1]> .s
> {:ok, "shawa"}
We could use elem:
\ duplicating the tuple for later examples
xlerb[1]> dup 1 [ Kernel elem 2 ] elixir
xlerb[2]> .
"shawa"
But this isn’t so great - suppose we’re dealing with a map? Map.fetch!/2? What if that map is then a Keyword List? Or nesting?
A much more expressive solution is to lean into the BEAM’s pattern matching!
xlerb[1]> .s
> {:ok, "shawa"}
xlerb[1]> &{:ok, &1} unpack
xlerb[1]> .
"shawa"
This funky & syntax is cribbed directly from Elixir’s capture syntax for anonymous functions. In Elixir the indexed & variables represent the function parameters. In Xlerb we use them to denote where on the stack the matched values should go.
Under the hood it looks something like:
{:ok, s1} = pop(stack)
push(s1)
The patterns support any Elixir/Erlang term, indeed we can dramatically simplify our call to fetch the current user, with a map pattern:
xlerb[0]> [ System get_env 0 ] elixir
xlerb[1]> &{"USER" => &1} unpack .
"shawa"
Much cleaner!
Pack
There’s a really neat duality here - if we can map compound terms’ constituents onto positions on the stack for ‘unpacking’, we can do the inverse and map stack values into constituents of a new term!
more content to come