2 ms·
In Lisp an interpreter means something slightly different: it means an interpreter for s-expressions. It's not about a virtual machine interpreter or similar.
by lispm 8y ago
In Lisp an interpreter means something slightly different: it means an interpreter for s-expressions. It's not about a virtual machine interpreter or similar.
A Lisp interpreter runs directly the s-expressions. This is independent from the idea of evaluation. Evaluation could be implemented by an interpreter or by a compiler.
For example using an interpreter:
CL-USER 32 > (defun fak (n)
(if (zerop n)
1
(* n (fak (1- n)))))
FAK
Let's break into the function if the argument N is 0:
CL-USER 33 > (trace (fak :break (eql (first *traced-arglist*) 0)))
(FAK)
CL-USER 34 > (fak 5)
0 FAK > ...
>> N : 5
1 FAK > ...
>> N : 4
2 FAK > ...
>> N : 3
3 FAK > ...
>> N : 2
4 FAK > ...
>> N : 1
5 FAK > ...
>> N : 0
Break on entry to FAK with *TRACED-ARGLIST* (0).
1 (continue) Return from break.
2 Continue with trace removed.
3 Continue traced with break removed.
4 Continue and break when this function returns.
5 (abort) Return to top loop level 0.
Type :b for backtrace or :c <option number> to proceed.
Type :bug-form "<subject>" for a bug report template or :? for other options.
CL-USER 35 : 1 > :bq
FAK <- FAK <- FAK <- FAK <- FAK <- EVAL <- CAPI::CAPI-TOP-LEVEL-FUNCTION <- CAPI::INTERACTIVE-PANE-TOP-LOOP
<- MP::PROCESS-SG-FUNCTION
CL-USER 36 : 1 > :n
Interpreted call to FAK
CL-USER 37 : 1 > :lambda
(LAMBDA (N) (DECLARE (SYSTEM::SOURCE-LEVEL #<EQ Hash Table{0} 41B01C37FB>))
(DECLARE (LAMBDA-NAME FAK))
(IF (ZEROP N) 1 (* N (FAK #))))
You see above the actual s-expression being executed for that stack frame. It's not executing any compiled or translated code. It's actually interpreting the source directly without any such step.
If we want, we could inspect, alter it with the usual Lisp functions and continue running.
CL-USER 39 : 1 > (fifth *)
(IF (ZEROP N) 1 (* N (FAK (1- N))))
CL-USER 40 : 1 > (setf (third *) 2)
2
CL-USER 41 : 1 > **
(IF (ZEROP N) 2 (* N (FAK (1- N))))
CL-USER 42 : 1 > :c 1
5 FAK < ...
<< VALUE-0 : 2
4 FAK < ...
<< VALUE-0 : 2
3 FAK < ...
<< VALUE-0 : 4
2 FAK < ...
<< VALUE-0 : 12
1 FAK < ...
<< VALUE-0 : 48
0 FAK < ...
<< VALUE-0 : 240
240
> I still fail to see what (Common) Lisp runtime gives over JVM
More efficient data representation, more efficient execution, saving and loading of images, tailored GCs, mixing compiled and interpreted (see above) Lisp code, deeper runtime inspection, resumeable exceptions, efficient stack traces, efficient function calls, fast startup times, etc etc.
Something like Lisp, which may have a bunch of very dynamic parts, is hard to implement efficiently on the JVM. Clojure is designed to map better to the JVM.