4 ms·
I really like Kernel. John Shutt's thesis language. It throws away a bunch of incidental complexity from scheme, most notably the minor disaster of hygienic mac
by JonChesterfield 3y ago
I really like Kernel. John Shutt's thesis language. It throws away a bunch of incidental complexity from scheme, most notably the minor disaster of hygienic macros. It follows a minor tangent on cyclic data which I'm not convinced matters very much.
Implementations are a bit DIY.
An interesting play would be to implement rsr7 scheme in kernel, semi-metacircular fashion.
- spindle 3y agoDoes picolisp scratch that itch for you?
- mst 3y agoKernel is operative rather than applicative - i.e. fexpr-based - and I don't think you can get something quite the same without it. (arguably a macro is really just a limited fexpr that's executed and the results inlined at compile time, though I mean that as 'morally equivalent' rather than making a technical claim since I haven't attempted to implement that in my fexpr based interpreters yet)
- JonChesterfield 3y agoDid you go with first class environments? If so defmacro builds a fexpr with an an extra eval in the dynamic environment plus a flag to tell the compiler it must be inlined (and that various other things should be reported as semantic errors). You can get somewhat close to fexpr with lazy evaluation but it turns out that's not the same thing either. Taking the arguments apart and building different things out of them is a superset of stashing it somewhere to evaluate later. (lambda (x) ...) ; evaluate the argument in the caller, bind it to the name x (fexpr (x) ...) ; bind the argument to the name x (normal (x) ...) ; make a thunk out of the argument and the environment (macro (x) ...) ; bind the argument to x then do the force inline & extra eval on call It's interesting that macros are the one with a bunch of extra work to do after the call whereas fexpr does the bare minimum of adding stuff to the lexical environment. Lambda maps eval across the arguments, normal maps make-thunk across the arguments.
- JonChesterfield 3y agoPicolisp is excellent.
- msk-lywenn 3y agoCould you elaborate on how hygienic macros are a minor disaster?
- JonChesterfield 3y agoMacros achieve a limited version of a fexpr with much more complicated semantics. Hygienic macros take that a step further - you get implicit renaming of variables which is generally convenient - in exchange for even more complicated semantics. The abstraction leaks as well. `(reduce and (list #t #t #f))` is probably an error. Calling a macro and calling a function looks the same and sometimes is the same and sometimes falls over. Macros are sacrosanct to lisp. Hygienic macros are a crown jewel of scheme. They're still the wrong thing though. In the beginning there was dynamic scope, possibly by accident. There were also fexpr - pass the unevaluated data and the environment, instead of passing evaluated data, which were also dynamically scoped. Sometimes called nlambda. That was difficult to program with and very difficult to compile. Macros are easier to use than dynamically scoped fexpr. They're much easier to compile and lisp was getting a bit of a kicking for being too slow. There were some papers written, macros were the better choice, and here we are. Lexical scoping turned up a little while after macros won the fight. Lexically scoped fexpr with first class environments are the right thing. Simpler and more capable than macros. First class environments being another thing sacrificed on the alter of performance decades ago. Shutt noticed this and wrote about it at length. It's slightly subtle that a non-hygienic macro is a subset of fexpr. Force inline it at the caller, refuse to run various calls (e.g. pass it to functions), wrap the return value in an eval in the caller environment. A hygienic macro has to do reflective symbol renaming stuff which is also expressible as a fexpr by implementing the symbol renaming rules of scheme, which thus far I don't have the patience for. Qualified as minor, in that the wrong thing we have is still very useful. Disaster in the sense that we could have fexpr if history had happened in a slightly different sequence. Opportunity in that lisp can be better. First class environments and first class macros can be done. The performance constraints of the past have been removed by hardware progress and to a lesser extent by progress in compiler design.
- deleted 3y ago[deleted]