Introduction

If you are coming here, and plan to read this book, it is probably because you're doing some research, looking for a new language to learn.

You came to the right place.

Throughout this book you'll discover Lisp, the authentic Lisp lost for the last 25 years.

PicoLisp has everything that is needed for practical application development of today applications. It is ready, even considering how small and simple it is, to do fast, secure, elegant, and simple applications.

Whom is this book for?

You want to learn PicoLisp, and probably know other languages? PicoLisp was not intended to be newbie friendly, so this book might not be either.

Anyway, no profound programming experience is required. If you ever touched a dynamic language like Python, Perl, some Bash or even Scheme, it should be enough. If you knew Lisp, you'll be on steroids.

We'll try to be deep but clear, so we can be sure you understand the way PicoLisp is intended to be used, and to build applications rapidly. If you clearly understand what's under the hood in every moment, your experience with PicoLisp will explode. We hope you can learn and enjoy both PicoLisp and this book a lot!

Features

Picolisp has plenty of features, but none of them are designed to get in your way:

It is an interpreter only, there is no compilation.

Everybody's is talking about how good are compilers and how bad are interpreters, right?

Well… not. Compilers are not always good, and interpreters are not always bad.

Compilers add overhead to the programmer's head up to the point that most of the writing and thinking is actually because trying to convince the compiler to understand your thoughts.

There was a time in which interpreters were loved and appreciated, and people only used compilers when really needed. But then, C++ and alikes appeared in the scene, and erased languages that were perfectly capable, whose only sin was being (slightly) slower.

That approach continues until today, that even scripting languages like Python and Perl are compiled. Common Lisp also followed that trend.

What's good and bad about a compiler?

First of all, writing a compiler that behaves like an interpreter is a very difficult task. That's why the Common Lisp specification relax in some requirement about functions and data available in compilation time.

If we take the CL compiler as an example, we see that actually it is a real mess. In CL, you can't define a function that is used in a macro in the same file, unless you use the function "eval-when", which itself turns to be also a mess to use. What is even worse, "eval-when" is not acting consistently across implementations, and certainly it does not do the same when you use CL in interpreted or compiled mode.

Another problem with compilers is that when you redefine a function, you must propagate the changes all along your code, or your code will be using the old one.

Some technology has been created to make a compiler behave almost as if it were an interpreter, for example, by using automatic propagation of redefinitions. Anyway most language implementations don't. Even if there are languages that do it, they must recompile code on the fly, which is usually not a very fast process, so making the whole experience slower that using a simple interpreter.

Anyway, sometimes, compilers are desirable and preferable. The main reason to use a compiler is to gain speed in numerical and binary operations.

Picolisp interpreter

Basically, Picolisp is "eval".

Using Picolisp, you are not afraid of using eval at all, because there is almost no penalty on using it. Example:

(de fibo (N)
   (if (lt0 N)
      (quit "Illegal argument" N) )
   (recur (N)
      (if (> 2 N)
         1
         (+ (recurse (dec N)) (recurse (- N 2))) ) ) )


Defining recur as:

(de recur recurse
   (run (cdr recurse)) )


Note how 'recur' dynamically defines the function 'recurse' at runtime, by binding the rest of the expression (i.e. the body of the 'recur' statement) to the symbol 'recurse'.

That would be impossible to define that way in Java or C, and in CL you need a macro, but the problem is that in CL "eval" costs a recompilation (which is usually slow) or execute it in interpreted mode, which is ussually also very expensive. In CL:

(defmacro recur (n &body body)
  `(labels ((recurse (n)
              ,@body))
    (recurse ,n)))


But one disavantage of this solutions is that code must reside in the same function. Otherwise you should use defun instead of labels but then that is not very idiomatic and could produce conflicts, and the worst thing, "eval-when" problems.

Another example is if2, in Picolisp:

(undef 'if2)  # Undefine the built-in 'if2'

(de if2 "P"
   (if (eval (pop '"P"))
      (eval ((if (eval (car "P")) cadr caddr) "P"))
      (if (eval (car "P"))
         (eval (cadddr "P"))
         (run (cddddr "P")) ) ) )


And in CL:

(defmacro if2 (cond1 cond2 both first second &rest neither)
  (let ((cond2V ,cond2))
    `(if ,cond1 (if cond2V ,both   ,first)
                (if cond2V ,second ,@neither))))


Aparently, CL version is shorter, but its functionality is also shorter because you need a temporary variable and duplicate code, which defies the advantages of an hypothetical if2.

These are just simple examples, and in real life the advantages are really huge. The main advantage is related to the fact that you can call functions which are not yet defined or stored somewhere else without warnings and/or performance compromises. In Picolisp you're not worried about storing code in databases or other media and manipulate it on the fly and then execute it at full speed. CL and other languages like Python and Perl try to do this up to some extent, but usually fail and do not have the same dynamic abilities as Picolisp has. Some of them even warn you against using it whenever you can.

Integrated Database

Database functionality is built into the core of the language. PicoLisp is a database query and manipulation language.

Database entities are first class objects. They are called "external symbols", because they are automatically fetched from database files when accessed, but otherwise behave like normal symbols.

This fetching from external files is completely transparent, the symbols "are just there", and there is no need (or even a function) to read or write them explicitly.

It is possible with PicoLisp to build large multi-user databases, distributed across many machines or in a cloud. Such a database system can be optimally fine-tuned, because all its levels are under the developer's control.

TODO: an example, and compare to other database interfaces.

http://picolisp.com/wiki/?bookintro

15may17    abu