with builtins; let
simpl = e: if isS e then resolve e.stack else e;
isS = s: s.type or "" == "$";
resolve = stack:
assert stack != [];
let ss = map simpl stack;
in foldl' (f: a: a f) (head ss) (tail ss);
export = {
S = {
type = "$";
stack = [];
__toString = self: "$${self.stack}";
__functor = self: arg: (
if arg == s:e
then resolve self.stack
else self // {
stack =
if self.stack == [] then [arg] else
if isS arg then [arg] ++ self.stack else
[(head self.stack arg)] ++ tail self.stack;
});
};
};
in
# tests
with export;
assert S map (a: a + 1) S map (a: a * 2) S map (a: a - 2) [1 2 3 4] s:e == [ (-1) 1 3 5 ];
assert S map (a: a * 2) S [1 2 3 4] s:e == [ 2 4 6 8 ];
# /tests
export
S
is an equivalent of $
, and s:e unwraps S
functor to value, and can be thought as a closing bracket)
Implementation is quite trivial, but I hope this example will encourage you to try implementing your own interesting custom stack executors for Nix, and making language more rich)
Please, share ideas in the comments!