For what it's worth, I've abstracted away the parameter simulation and put it in dyn.arc, which is where Lathe's dynamic box API is kept. Now you can define your own "secretargs" with default values and have it automatically seem like they're passed to every function in the language. It's not necessarily pretty; the point is to build things like 'failcall on top of it.
; Surprise, this code has been tested!
(= lathe-dir* "your/path/to/lathe/arc/")
(load:+ lathe-dir* "loadfirst.arc")
(use-rels-as dy (+ lathe-dir* "dyn.arc"))
(= secret1 (dy.secretarg 4))
(= secret2 (dy.secretarg 5))
(= secret3 (dy.secretarg 6))
(dy:call-w/secrets (dy:secretarg-fn (a b c)
(list a b c d e (dy.secretargs)))
(list (list secret1 9)
(list secret3 200))
1 2 3)
=> (1 2 3 9 5 ((#(tagged ...) 9) (#(tagged ...) 200)))
There's a catch, though, which is that general-purpose function-calling functions like 'apply and 'memo don't propagate secretargs, and there's probably nothing I can do about that aside from hacking on the language core. This is the same kind of compatibility-breaking I brought up when we were talking about keyword arguments.
Fortunately, secretargs are pretty general-purpose--they're pretty much just keyword arguments with non-symbol keys--so things like keyword argument systems can be implemented on top of them. Just make a secretarg that stores a special-purpose keyword map.
I'm not sure if that'll come up in Lathe for a long time, though. For now the only benefit is that it's a little easier to explain 'failcall and 'failfn: they use a non-symbol keyword argument (a secretarg) to communicate, and 'failfn makes that argument into a more natural failsafe by chaining it to an escape continuation.