argument stack ((: 1 1) (: (+ 2 3) (COMPILED CODE)) (+ 2 3) : (COMPILED CODE) 1 : 1 strategy stack (NAME NAME) NAME NAME so there'll be an N for the argument stack, and N for the strategy stack 3 : 3 2 : 2 (+ 2 3) : (COMPILED CODE) 1 : 1 ARG (1 : 1) ARG ((+ 2 3) : (ARG 2 ARG 3 APPLY + 2)) APPLY + 2 # won't know size of strategy stack until call time (+ 1 (* 2 3)) ARG (: 1 1) ARG (: (+ 2 3) (ARG (: 2 2) ARG (: 3 3) APPLY + 2)) APPLY * 2 (+ 1 (* 2 3)) NARG 1 ARG (: (+ 2 3) (NARG 2 NARG 3 APPLY + 2)) APPLY * 2 (+ 1 (* a 3)) ARG (: 1 1) ARG (: (+ 2 3) (VARG a ARG (: 3 3) APPLY + 2)) APPLY * 2 Keccak-256("The quick brown fox jumps over the lazy dog.") 0x 578951e24efd62a3d63a86f7cd19aaa53c898fe287d2552133220370240b572d >>> hash = "578951e24efd62a3d63a86f7cd19aaa53c898fe287d2552133220370240b572d" >>> base64.b64encode(bytes.fromhex(hash)) b'V4lR4k79YqPWOob3zRmqpTyJj+KH0lUhMyIDcCQLVy0=' #V4lR4k79YqPWOob3zRmqpTyJj+KH0lUhMyIDcCQLVy0= (# 1 2) (closure (a) (+ a 1)) compiled = # (+ 1 (# 1)) compiler can look up + at compile time (stored as a mapping in bindings passed at start of compilation) # can also be looked up at compile time so this obviates the call-by-name problem (+ a 1) so the runtime will mostly just be replacing variables and running primitives essentially when a closure is called, there are *only* the argspec bindings only problem is then you kind of don't have higher order functions i.e. you can't call a function. couldn't make "compose", for example (closure (f g) (closure (a) (f (g a)))) could perhaps do this by manipulating data as code that way, you'd just be making runtime macros in a way so, define compose as something like... (compose ) => ( ( )) basically a regular macro, actually (# ) hmm, what if it's already been compiled? well, you could only compile it if the definition of # is known so basically you just get more creative compilation so instead of regular NAME, VALUE arguments, you have PATTERN arguments (# 1 2) should break (# # #) should work outputs (closure (a) (# (# a)))