If there is no difference between reading, compilation, and runtime in Lisp, can someone give me some intuitive examples?

As I read the blog Revenge of Nerds , it says (which is where Lisp made another section):

The whole language is there all the time. There is no real difference between read time, compile time and run time. You can compile or run code while reading, reading, or running code while compiling, and reading or compiling code at runtime.

Running code while reading allows users to reprogram Lisp syntax; executable code at compile time is the basis of macros; runtime compilation is the basis for Lisp use as an extension language in programs such as Emacs; and reading at runtime allows programs to communicate using s-expressions, an idea recently invented as XML.

To understand this sentence, I draw a state diagram :

read / compile / runtime in Lisp

I have two questions:

  • how to understand to read at runtime enable programming to communicate using s-expression, an idea reinvented as XML

  • what can we do when compiling at read time or reading at compile time?
+3


source to share


2 answers


XML allows you to exchange data at runtime between programs (or between different calls to the same program). The same goes for JSON, which is a subset of Javascript and is a little closer to Lisp in spirit. However, Common Lisp gives you more control over how the various steps are performed; as explained in quotes, you can reuse the same tools as your Lisp environment, rather than create a framework like other languages.

Basically, you are printing data to a file:

(with-open-file (out file :direction :output)
  (write data :stream out :readably t))

      

... and you will restore it later:



(with-open-file (in file) (read in))

      

You call this "serialization" or "sorting" in other languages ​​(and in fact in some Lisp libraries). The step READ

is customizable: you can read data written in custom syntax ( JSON.parse

takes a reviver function, so it's a bit similar, a Lisp reader works for regular code as well). For example, the local-time library has special syntax for dates that can be used to rebuild a date object from a stream.

In practice, this is a bit tricky because not all data is in a simple readable form (how to keep the network connection?), But you can write forms that can restore information when it is loaded (for example, reconnect). So Lisp allows you to customize READ

and PRINT

, with readtables and PRINT-OBJECT

, but there is also LOAD-TIME-VALUE

and MAKE-LOAD-FORM

, which allows you to allocate objects and initialize them when the code is loaded. All of this is already available in this language, but there are also libraries that make things easier, like cl-conspack : you simply store the classes in files and load them back without having to define anything special (assuming all slots are preserved). This works well thanks to the meta-object protocol.

+2


source


Common Lisp

READ is a function that reads s-expressions and returns Lisp data.

CL-USER> (read)
(defun example (n) (if (zerop n) 1 (* (example (1- n)) n)))  ; <- input
(DEFUN EXAMPLE (N) (IF (ZEROP N) 1 (* (EXAMPLE (1- N)) N)))  ; <- output

      

Last result again:

CL-USER> *
(DEFUN EXAMPLE (N) (IF (ZEROP N) 1 (* (EXAMPLE (1- N)) N)))                                                                                                       

      

Setting a variable code

to the last result.

CL-USER> (setf code *)
(DEFUN EXAMPLE (N) (IF (ZEROP N) 1 (* (EXAMPLE (1- N)) N)))                                                                                                       

      

What is the third element?

CL-USER> (third code)
(N)                   

      

We can evaluate this list as it looks like actual Lisp code:

CL-USER> (eval code)
EXAMPLE                                                    

      

The function is defined EXAMPLE

. Let's get the function object:

CL-USER> (function example)
#<interpreted function EXAMPLE 21ADA5B2>                           

      



This is an interpreted function. We are using the Lisp interpreter.

Use the function by matching it over the list:

CL-USER> (mapcar (function example) '(1 2 3 4 5))
(1 2 6 24 120)                                      

      

Compile the function:

CL-USER> (compile 'example)
EXAMPLE                                                                                                                                                           
NIL                                                                                                                                                               
NIL                    

      

The function was compiled successfully. The compiler has no warnings and the function should now run much faster.

Try again:

CL-USER> (mapcar (function example) '(1 2 3 4 5))
(1 2 6 24 120) 

      

This is the same result, but is probably much faster to compute.

Since it is now compiled, let's parse the function:

CL-USER> (disassemble #'example)
0          : #xE3E06A03 : mvn            tmp1, #12288                                                                                                             
4          : #xE18D6626 : orr            tmp1, sp, tmp1, lsr #12                                                                                                  
8          : #xE5166030 : ldr            tmp1, [tmp1, #-48]                                                                                                       

      

... and a lot more lines of ARM assembler machine code

+2


source







All Articles