3 ms·
By Emacs do you mean Elisp? Your session there is not surprising to me. I don't have emacs handy but what does this do? ((lambda (f) (f)) (lambd
by akkartik 5y ago
By Emacs do you mean Elisp? Your session there is not surprising to me. I don't have emacs handy but what does this do?
((lambda (f)
(f))
(lambda() 42))
You might need to throw a 'funcall in there or something, but my hypothesis is that this will work (return 42) without needing the top-level argument to be quoted. 'lambda is a deep special case, basically.
I understand that functions always zip through their arguments, evaluating each one. But when you quote the args in the call, I tend to expect the arguments to not be evaluated within 'evlis.
I'm surprised that quoting args makes the interpreter smaller! That's pretty interesting. But I think this interpreter will have some behavior that is surprising to anyone used to all extant lisps for examples like this:
((lambda (sym)
(cons sym 3))
(quote a))
Here there's no binding for 'a. I expect this to return (a . 3) in JMC's original Lisp.
- anderskaseorg 5y agoThe lambdas are quoted because they’re lambdas, not because they’re arguments. In a more fully-featured Lisp, the code (LAMBDA () 42) would evaluate to a special function data type with no direct representation in terms of cons cells. That’s a luxury this implementation can’t afford, so its data representation of a function is the same as its code representation: a cons cell whose car is the atom LAMBDA. With this design, the code (LAMBDA () 42) would be self-evaluating: it would evaluate to the same thing as the code (QUOTE (LAMBDA () 42)). But since the latter syntax works, there’s no need to waste bytes supporting the former syntax. In the absence of that special support, the default meaning of the code (LAMBDA () 42) is to call a function named LAMBDA, just like the code (FOO () 42) calls a function named FOO.
- akkartik 5y agoI see. Kinda. The 'lambda in the first line isn't quoted. And the eval itself seems identical to JMC. So this is just the substrate level and only when evaluating args? Does that seem right?
- jart 5y agoThe first item in the list is evaluated, just like the other items in the list. For example: ((LAMBDA (ARG1 ARG2 ARG3) <YOUR PROGRAM GOES HERE>) (QUOTE VAL1) (QUOTE VAL2) (QUOTE VAL3)) Is the same syntax as a normal function call: (PROGRAM (QUOTE VAL1) (QUOTE VAL2) (QUOTE VAL3)) The only difference is that, since it's the root-level program, the binding of the name PROGRAM can't have happened yet. So it's simply inlined into the expression. The Apply() part of the evaluator has a special case for recognizing this, which causes evaluation of the first argument to terminate: int Apply(int fn, int x, int a) { int t1, si, ax; if (ISATOM(fn)) { switch (fn) { case ATOM_CAR: return Car(Car(x)); case ATOM_CDR: return Cdr(Car(x)); case ATOM_ATOM: return ISATOM(Car(x)) ? ATOM_T : NIL; case ATOM_CONS: return Cons(Car(x), Car(Cdr(x))); case ATOM_EQ: return Car(x) == Car(Cdr(x)) ? ATOM_T : NIL; default: // recurse to turn (FUNC ARG1 ARG2) into ((LAMBDA ...) ARG1 ARG2) return Apply(Eval(fn, a), x, a); } } // evaluate ((LAMBDA ...) ARG1 ARG2) if (Car(fn) == ATOM_LAMBDA) { t1 = Cdr(fn); si = Pairlis(Car(t1), x, a); ax = Car(Cdr(t1)); return Eval(ax, si); } return UNDEFINED; } The Eval() function which calls Apply() has already evaluated all the list items except for the first one, which is left to Apply() to figure out. The reason why things are this way is because, in order to save space, the REPL loop doesn't maintain a persistent set of global variables. Due to the NIL here, each expression is its own hermetic job: void Repl(void) { for (;;) { Print(Eval(Read(), NIL)); } } If you changed that NIL to be an alist that's populated by things like defun / setq / etc. in the global scope, then the usability of the language improves dramatically. We didn't do it due to the singular focus on size. But at the same time that simply means we left fun opportunities for improvement to anyone wishing to hack on the codebase and make it their own.
- akkartik 5y agoOk that makes sense. Thanks!