1. Getting Started: A Quick Tutorial

Author(s): Yann LeCun

By following through the subsections of this section, and trying out the code examples and commands given, the users will be well on their way towards using Lush.



1.0. Installation on Linux/UNIX


Get the tarball from http://sourceforge.net/projects/lush , cd to a convenient place (say /home/your-home-directory or /usr/local) and unpack the tarball. Then cd to lush and type ./configure then make . If you want to install the Lush executable so that all users on your machine have access to Lush, su to root, and type make install . Otherwise, simply add lush/bin to your shell path.

Compilation and installation of Lush requires certain packages and libraries be available on your system. In particular, you need libiberty.a, which is not installed by default on Mac OS-X and on certain Linux distributions. Most distros have that prepackaged in libbinutils or libbinutils-devel, or libbinutils2-devel (e.g. Mandriva Linux(2005 LE) has it in libbinutils2-devel-2.15.90.0.3-1mdk). Never download and install another version of libbinutils than the one designed for you distro or bad things may happen.

To enjoy the full capabilities of Lush, you may also want to install the Gnu Scientific Library (GSL or libGSL). Most Linux distros have it in two packages libgsl or libgsl0 and libgsl-devel or libgsl0-devel. LibGSL can also be installed from source, which can be obtained at http://sources.redhat.com/gsl

Another nice optional package to install is libSDL and its development libraries (e.g. on Mandriva Linux libSDL1.2-1.2.7-9mdk and libSDL1.2-devel-1.2.7-9mdk). It is also preferrable to set up OpenGL correctly on your machine (include the development packages when installing OpenGL).



1.1. Starting Lush


If the lush executable was installed in your path, you can start lush by simply typing lush at the Unix prompt. Otherwise you can make a symbolic link from anywhere in your path to where the lush executable resides (most likely /usr/local/lush/bin/lush or /wherever-you-installed-lush/bin/lush )
 amiga% lush
LUSH Lisp Universal Shell (compiled on Oct 17 2004)
   Copyright (C) 2002 Leon Bottou, Yann Le Cun, AT&T Corp, NECI.
 Includes parts of TL3
   Copyright (C) 1987-1999 Leon Bottou and Neuristique.
 Includes selected parts of SN3.2:
   Copyright (C) 1991-2001 AT&T Corp.
This program is free software; it is distributed under the terms
of the GNU Public Licence (GPL) with ABSOLUTELY NO WARRANTY.
Type `(helptool)' for details.
+[/home/yann/lush/sys/stdenv.dump]
 [lushrc.lsh]
? 

To exit Lush, press Control-D or enter (exit) at the Lush prompt.

If you have emacs installed on your system, it is highly recommended to run Lush from within Emacs so that you may enjoy such niceties as command-line editing, history, and IDE-like features. See the next section "Configuration" for details on how to do this.



1.2. Configuration


Lush can be run from the shell prompt. It provides command line editing, history, and symbol and file name completion.

Many will prefer to run Lush under Emacs. To make this convenient, the following line should be added to the .emacs file in your home directory:

  (load "your-lush-dir/etc/lush.el")
This file provides two functionalities in Emacs:

Emacs's Lisp/Lush mode provides a set of nice command to facilitate Lisp programming. Among them are C-M-e (Ctrl-Meta-e) to jump to the end of a function, C-M-a to jump to the beginning, C-M-q to indent/format a function, and C-M-x to send the function or expression in which the cursor is to the interpreter (assuming it is running in the *inferior-lisp* buffer).



1.3. Reporting Bugs and Problems


If you encounter a bug or want to signal a problem, go to: http://sourceforge.net/tracker/?atid=410163&group_id=34223&func=browse , click "Submit New", and enter a bug report

If you want to request a new feature, go to http://sourceforge.net/tracker/?atid=410166&group_id=34223&func=browse , and click "Submit New".



1.4. Getting Help and Documentation Browsing


Lush has an on-line documentation system. It can be invoked by typing (helptool) at the Lush prompt, which will popup a graphic browser window with the manual. A non-graphic version of the on-line help can be invoked by typing ^Atopic for help on functions or concepts whose name include topic (the ^A can be typed either as Caret and A or as Control-A, but the latter form is inconvenient when running Lush within Emacs). Here is an example:
  ? ^Aregex
  Search Results for: regex
    1. Regular Expressions (regex).
    2. (regex-match <r> <s>)
    3. (regex-extract <r> <s>)
    4. (regex-seek <r> <s> [<start>])
    5. (regex-subst <r> <s> <str>)
    6. (regex-rseek <r> <s> [<n> [<gr>]])
    7. (regex-split  <r> <s> [<n> [<gr> [<neg>]]])
    8. (regex-skip  <r> <s> [<n> [<gr> [<neg>]]])
    9. (regex-count <r> <s>)
   10. (regex-tail <r> <s> [<n> [<gr> [<neg>]]])
   11. (regex-member <rl> <s>)
   12. (glob <regex> <l>)
  choice? 2
  ------------------------------------------------------------------------
  (regex-match <r> <s>)                         [DX]
  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
  
   Returns <t> if regular expression <r> exactly matches the entire string
  <s>.  Returns the empty list otherwise.
   Example:
  ? (regex_match "(+|-)?[0-9]+(\\.[0-9]*)?" "-56")
  = t
  
  = ()
  ? 

The list of symbols whose name contains a particular string can be listed using "^Ssymbolstring".

  ? ^Sregex
  cleanup-regex      regex              regex-count        regex-member
  regex-rseek        regex-skip         regex-split        regex-tail
  regex_extract      regex_match        regex_seek         regex_subst
  
  = ()



1.5. Basic Syntax


The Lush syntax is probably one of the simplest you will find in any programming languages. It is based on Lisp. Don't be scared away by the word "Lisp"! Lush is probably one of the easiest-to-learn language you will ever encounter. The big idea is that every expression is a list enclosed in parentheses which, when "evaluated", returns a result. The first element of the list is the function being called, and the remaining elements are its arguments. So instead of typing sqrt(4) to call the square root function like in C, you type (sqrt 4) .

Here is an example of how an expression typed at the Lush prompt is evaluated and its result printed:

  ? (sqrt 4)
  = 2

The list notation is also used for what we generally think of as infix operators, which in Lush (and other Lisps) are just functions like any other. Instead of writing 3+4 , we write (+ 3 4) :

  ? (+ 3 4)
  = 7

Arguments of most functions are evaluated before the function is called, which allows nested expression:

  ? (sqrt (+ 3 4))
  = 2.6458

Words like sqrt or + in the previous example are called symbols. Symbols can be assigned a value. The value of the symbol sqrt in the above example is a function that returns the square root of its argument. The value of a symbol can be assigned to any lisp object, and therefore is used as the basic mechanism for variables. Assigning a value to a symbol is generally performed with the function setq :

  ? (setq x 5)
  = 5
  ? (* x x)
  = 25
  ? (setq x "cou")
  = "cou"
  ? (setq x (concat x x))
  = "coucou"

When not assigned to a value, symbols contain nil , which is printed as (and equivalent to) the empty list " () ". The empty list nil is used to represent the value "FALSE" returned by a boolean expression like

  (> (- 2 4) 1)
  = ()

Variables can be set to any type of Lush object. In interpreted mode, the types of the variables need not be declared, but they must be declared if the code is to be compiled (more on that later). Variables can be assigned numbers, matrices and vectors, strings, lists, functions, macros, classes, hash table, and several other predefined objects types (such as windows and files), as well as user-defined objects (instances of user-defined classes).



1.5.0. Symbol Names and Special Characters


Symbol names in Lush are case-insensitive (i.e. SQRT and sqrt are the same variable). Lush makes no difference between underscores and dashes (hyphens) in symbol names. So idx-sum is the same as idx_sum . Symbol names cannot contain certain characters: parentheses, spaces, forward and backward quotes, commas, curly braces, square brackets, hash, caret, tilde, and control characters. Those characters play special roles in the Lush reader.

By convention, sub-words of a symbol name are often delimited by hyphens and occasionally by dots:

  gsl-my-new-pointer   brace.read 



1.6. Basic Types


Lush has a small number of basic types, a number of not-so-basic built-in types, and a mechanism for creating new types (classes). The basic types include numbers (stored as 8-byte double-precision floating point numbers), generic pointers, and list cells. The not-so-basic types include strings, symbols, seven major types of functions (called DE, DF, DM, DX, DY, DH, and DZ), nine types of vector storage structures (for storing bytes, unsigned bytes, shorts, ints, floats, doubles, generic pointers, and lisp objects), one type of vector/matrix/tensor access structure, two types of file descriptors, hash tables, graphic windows, classes, and dates. New types with slots and methods (a la C++) can also be defined by deriving from the base class object .

Some of the types can be entered as literals:

Numbers and strings have the interesting property that they evaluate to themselves, i.e. they return themselves when typed on the line or in an expression. On the other hand, symbols evaluate to their assigned value, and lists evaluate to the result of applying their first element (interpreted as a function) to the rest of the elements (the arguments). That's why the symbol and the list in the above example are preceded by a quote. The quote prevents what follows from being evaluated. Without the quote coucou would return its value (or the empty list () if it has no value), while (1 2 3) would produce an error because 1 is not a function.



1.7. Function Definitions


Functions can be defined in many ways, but the most common one is to use the de construct (similar to the defun construct in most other Lisps). The general form is:
(de <name> (<arg1>....<argn>) <body1>....<bodym>)

Here is a specific example:

  ? (de square (x) (* x x))
  = square
  ? (square 4)
  = 16

This definition should be interpreted as follows. de means "define function", it is followed by the function name " square ", a list of formal arguments (x) , and the body of the function (* x x) , which means multiply x by itself and return the result. The return value of the function is the value returned by the last evaluation in the body bodym .

The definition of a particualr function can be displayed by typing ^Pfunctionname :

  ? ^Psquare
  (de square (x)
    (* x x) )
  = t

The directive "^P", like "^A" introduced earlier is a so-called macro-character. Macro-characters are special combinations of characters that are translated into function calls by the interpreter. Lush has several predefined macro-characters to reduce typing for several commonly used interactive functionalities. A particularly useful one is "^Lfilename" which loads a Lisp source file (more on this later).



1.8. Loops, Conditionals, Local Variables, and Such


Lush provides traditional loop constructs such as for , while , repeat , an so on. Here is an example of how to compute the sum of the inverses of the first 10 integers (i.e. the 10th term of the harmonic series).
  ? (setq z 0)
  = 0
  ? (setq i 0)
  = 0
  ? (while (< i 10) (incr i) (incr z (/ i)))
  = 2.929

the function incr increments its first argument by the value of its second argument, or by 1 if the second argument is not present, and returns the result. The function / called with one argument returns its inverse.

The above example is quite awful because it leaves two global variables i and z laying around for no reason. A cleaner way of doing things consists in using temporary variables that are automatically destroyed when they are no longer needed. This is done with the let* construct:

 (let* ((z 0) (i 0))
   (while (< i 10) (incr i) (incr z (/ i))))

In its most general form, the let* construct is used as follows:

  (let* ((<var1> <value1>) ... (<varN> <valueN>)) 
        <body1> ... <bodyP>)

It creates temporary local variable var1 ... varN , sets them to the values value1 ... valueN respectively, evaluates body1 ... bodyP and returns the result of the evaluation of bodyP . The values of the variables are destroyed upon exiting the let* . In fact, if a temporary variable created in a let* has the same name as a preexisting variable, the preexisting value will be temporary "masked" during the life of the temporary variable. The preexisting value will be restored upon exit:

(setq z 345)
= 345
?  (let* ((z 0) (i 0)) (while (< i 10) (incr i) (incr z (/ i))))
= 2.929
? z
= 345

For the interested reader, Lush uses "dynamic variable binding", in contrast with many other languages (particularly compiled ones) that use lexical scoping.

The code above can be encapsulated in a function using the de construct:

  ? ;; compute the n-th term of the harmonic series
  ? (de harmonic (n) 
        (let* ((z 0) (i 0)) (while (< i n) (incr i) (incr z (/ i)))))
  = harmonic
  ? (harmonic 10)
  = 2.929
  ? (printf "%18.14f\n" (harmonic 10))
    2.92896825396825
  = ()

In Lush, the text that follows one or several semi-colons on a line is taken as comments and ignored by the interpreter.

Conditional constructs include if , when , cond , and selectq . The basic form of the if construct is as follows:

  (if <conditional-expression>
      <evaluate-if-non-nil>
    <evaluates-if-nil-1>
    <evaluates-if-nil-2>
    .....
    <evaluates-if-nil-n>)

If the conditional expression returns a non-nil result, the expression evaluate-if-non-nil is evaluated and its result returned. If it returns nil, the remaining expressions are evaluated, and the result of the last one is returned. Multiple expressions can be grouped in the evaluate-if-non-nil part by grouping them in a progn construct: (progn expr1 ... exprN ) . To illustrate the use of if , here is a particularly stupid but didactic implementation of a function that compute the n-th Fibonacci number:

  (de fibo (n) 
    (if (= n 0)            ; test if n equals 0
       0                   ; if yes, return 0
      (if (= n 1)          ; else test if n equals 1
         1                 ; if yes return 1
        (+ (fibo (- n 1)) (fibo (- n 2)))))) 

This is an example of recursive function (a function that calls itself), a concept dear to the heart of many Lisp aficionados, but whose usage is somewhat discouraged in Lush (the Lush interpreter likes recursive functions, but the Lush compiler doesn't like them at all).



1.9. Function Compilation


To improve execution speed, certain Lush functions can be compiled. In order to compile functions they must be written according to the rules of Compiled Lush (CLush). The Lush compiler for CLush has specific features and limitations that conspire to make CLush a distinct language, different from interpreted Lush in several ways.

For starters, to avoid inefficient run-time type-checking in compiled code, one must define the type of all the variables before a function can be compiled. The compilable version of harmonic is:

  ? ;; define the function
  ? (de harmonic (n)
        ((-double-) n)
        (let* ((z 0) (i 0))
         ((-double-) z i)
          (while (< i n) (incr i) (incr z (/ i)))))
  = harmonic

The lines ((-double-) n) and ((-double-) z i) declare the type of the argument n and the local variables z , and i as double precision floating point numbers. Before we compile the function, let's measure the number of CPU seconds required to compute the sum of the million-th harmonic sum in interpreted mode (this is on a 800MHz Pentium running Linux):

? (time (harmonic 1000000))
= 2.05

We can compile the function by simply typing (dhc-make "junk" harmonic) . Lush will translate the Lisp code into C and write the C source into the file "C/junk.c". The C compiler will then compile the code and generate the object file "C/ architecture /file.o", where architecture is the name of the architecture on which Lush is currently running (e.g. i686-pc-linux-gnu). This allows to maintain object files for different architectures in a single source directory tree. Then, Lush's dynamic loader will automagically load the object code back into the interpreter.

(dhc-make "junk" harmonic)
Preprocessing and parsing harmonic ...
Generating C for harmonic ...
gcc -DHAVE_CONFIG_H -I/home/yann/lush/include   -DNO_DEBUG -Wall -O3 -funroll-loops -mcpu=i686 -pthread -c /tmp/C/junk.c -o /tmp/C/i686-pc-linux-gnu/junk.o
= "/tmp/C/i686-pc-linux-gnu/junk.o"
Now let's see how many CPU seconds it takes to execute the compiled version of the code. We need to repeat the code a few times to get a meaningful figure:
  ? (time (repeat 50 (harmonic 1000000)))
  = 2.37
The speedup over the interpreted version is around 45. An important point to remember is that the interpreter always treats numbers as double precision floating point, while numbers in compiled code are treated as specified by their type declaration. Lush understands the following scalar types: -ubyte-, -byte-, -short-, -int-, -float-, -double-, -bool-, -gptr- . they correspond respectively to the C types unsigned char, signed char, short, int, float, double, unsigned char, void* .

Just for curiosity, let's look at the C code generated by Lush's Lisp to C compiler in current-dir/C/junk.c :

/*
 * FUNCTION harmonic
 */
extern_c real
C_harmonic (real L1_n)
{
  TRACE_PUSH ("C_harmonic");
  {
    real L_Tmp0;
    {
      real L2_1_z;
      real L2_2_i;
      L2_1_z = 0;
      L2_2_i = 0;
      L_Tmp0 = 0;
/* While loop */
      goto L_1;
    L_0:
      {
       L2_2_i = (L2_2_i + 1);
       L2_1_z = (L2_1_z + (1 / (real) L2_2_i));
       L_Tmp0 = L2_1_z;
      }
/* While loop test*/
    L_1:
      {
       if ((L2_2_i < L1_n))
         goto L_0;
      }
    }
    TRACE_POP ("C_harmonic");
    return L_Tmp0;
  }
}

It looks a bit funny with all these gotos , but it's reasonably simple and straightforward C code.



1.10. Program Files


The normal way to write Lush code is to open a file, say "toto.lsh", in your favorite editor, and to write all the necessary function definitions and compilation instructions in it. The file can then be loaded into the interpreter with (load "toto") . For example, a Lush file for the above function would contain:
  ;; a function that computes the sum of the inverses of the first n integers.
  (de harmonic (n)
      ((-double-) n)
      (let* ((z 0) (i 0))
       ((-double-) z i)
        (while (< i n) (incr i) (incr z (/ i)))))

  ;; compile the function to toto.c and toto.o
  ;; if the first arg is nil, the .c file has the same 
  ;; base name as the file being loaded.
  (dhc-make () harmonic)

When loading this file, Lush processes its content as if it were typed at the prompt. Therefore, loading this file will define harmonic, and then compile it. If you subsequently reload the same file, the compilation will only occur if the source file toto.lsh was modified since the last compilatione.

The use of GNUemacs to edit Lush files is very strongly recommended as it has a special Lisp mode that flashes matching parentheses, highlights keywords and comments, and automatically indents Lisp expressions (using ALT-CTRL-Q). More details on how to setup Emacs are given in the "setting things up" section of this tutorial.



1.11. On-Line Documentation


As we said earlier, Lush possesses an on-line documentation system. This system can be used by Lush users to document their own programs. Its use is strongly recommended. Documenting functions or other objects can be done with the ``#?'' macro-character. Here is what toto.lsh should have looked like in the first place:
  #? (harmonic <n>)
  ;; computes the sum of the inverses of the first <n> integers
  ? (de harmonic (n)
        ((-double-) n)
        (let* ((z 0) (i 0))
         ((-double-) z i)
          (while (< i n) (incr i) (incr z (/ i)))))
  
  ;; compile the function to toto.c and toto.o
  (dhc-make () harmonic)

The string after the "#?" is what will be searched when search feature of (helptool) is invoked on this file. Contiguous comment lines immediately following the "#?" line constitute the text of the help. After this file is loaded, the on-line help for harmonic and all the functions in the same file can be displayed with:

  (helptool "toto.lsh")



1.12. Multiple File Programs and Search Path


Sometimes, a Lisp program requires other Lisp files to be loaded in order to run. For example imagine that we have written a set of signal processing functions in the file "/home/yann/lsh/dsp.lsh" , and now we are writing a program "tutu.lsh" that uses some of those functions. The beginning of "tutu.lsh" would look like the following
  #? *** My Cool Signal Processing Application
  ;; this is my really cool dsp application.
  (libload "/home/yann/lsh/dsp")
  .....
(the .lsh extension is automatically added if required).

The function libload has an interesting features: it remembers which files were already libloaded and loads them only once into the interpreter (subsequent calls to libload with a previously libloaded file will have no effect). There is an exception to this behavior: libload keeps track of the tree of dependencies between Lush program files, and also keeps track of the times of last modification of each file. When a file is loaded with libload , all the files on which this file depends are also loaded, but only if they have been modified since last time they were libloaded. Here is a possible scenario: file A libloads files B and C. File A is libloaded, as a result file B and C are libloaded. File B is modified. File A is libloaded again, as a result B is re-libloaded, and A is re-libloaded. C is not re-libloaded since it was previously libloaded and was not modified. This behavior is recursive (it applies to all files directly or inderectly libloaded by A).

In certain cases, the lower-level function load may be preferable. load simply loads a file:

  ? (load "/home/yann/lsh/dsp")

Putting absolute path names in a program is generally a bad idea since programs have a pernicious tendency to move from time to time. The solution is to rely on Lush's search path mechanism. When any loading directive is executed, Lush looks for the file in the current directory, and then in the search path. The default search path includes lush/local , lush/packages , lush/lsh , lush/sys and several subdirectories of lush/lsh . The search path can be user-extended with the addpath function:

  (addpath "/home/yann/lsh")

now, loading "dsp.lsh" only requires:

  (libload "dsp")



1.13. C Function Calls from Lush


The ability to freely mix Lisp and C code is one of the most interesting features of Lush.

Let's say you have written a C file called titi.c with the following content:

  float sq(float x)
  {
    return x*x;
  }

You have compiled the file and produced the object file titi.o . Calling sq from the Lush interpreter is as simple as the following. First, dynamically load the object file into Lush

  ? (mod-load "titi.o")
then, write a lisp function whose only purpose is to call sq .
  ? (de square (x) ((-float-) x) 
        (cpheader "extern float sq(float);")
        (to-float #{ sq( $x ) #} ))

Here is what the above means: (de square (x) ...) means define a new Lisp function called square with a single argument x . ((-float-) x) simply declares x as float. (to-float ....) converts its argument to float (like a cast in C). The sequence #{ .... #} allows to insert C code within Lisp code. Therefore #{ sq( $x ) #} simply calls the C function sq and returns the result. Lisp variables can be inserted in in-line C code by prepending a Dollar sign, thus $x refers to the Lisp float variable x . The cpheader directive allows one to include a string in the "header" section of the C files generated by the Lisp to C compiler. We use it here to specify the type of the argument and the return value of sq .

We can now compile the above function using:

  ? (dhc-make () square)
Two file C/square.c and C/i686-pc-linux-gnu/square.o will be generated with the C source and the object code for square . The object code will be automatically loaded into Lush. Now square can be called from the Lisp interpreter:
  ? (square 5)
  = 25

In the above example, the to-float casting function was used to tell the compiler what type the returned value has. The following "cast" functions are available: to-float , to-int , to-double , to-bool , to-gptr . These functions cast their argument to the corresponding type.



1.14. Mixing Lisp and In-Line C Code


If we do not have a ready-made C file for our function, we can use the inline C capability to write code in C right inside the Lisp function. Here is how we could write the familiar harmonic function this way:
  (de harmonic (n)
    ((-double-) n)
    (let ((r 0))
      ((-double-) r)
      #{ { double i=0;
           while (i<$n){ i+=1.0; $r+=1/i; };
         } #} r))
(dhc-make () harmonic)
Preprocessing and parsing harmonic ...
Generating C for harmonic ...
gcc -DHAVE_CONFIG_H -I/home/yann/lush/include   -DNO_DEBUG -Wall -O3 -funroll-loops -mcpu=i686 -pthread -c /tmp/C/junk.c -o /tmp/C/i686-pc-linux-gnu/junk.o
= "/tmp/C/i686-pc-linux-gnu/junk.o"
? (time (repeat 50 (harmonic 1000000)))
= 2.36

That's about the same time as the version written in compiled Lisp. In this case, writing directly in inline C was not particularly advantageous, but there are cases where writing in Lisp is inefficient, awkward, or even outright impractical. In these cases one can resort to inline C implementations.



1.15. Lists


Lush belongs to the Lisp family, and therefore has lots of functions to manipulate lists. In fact, Lush programs themselves are lists. Lists are sequences of Lush objects enclosed in parentheses. Things like (+ 1 2) is a list. However, when the list (+ 1 2) is entered at the Lush prompt, it is immediately evaluated and discarded right away:
? (+ 1 2)
= 3

To create a list, we must prevent the evaluation from happening. This is done with the quote function or the "'" (quote) macro-character:

(quote (+ 1 2))
= (+ 1 2)
? '(+ 1 2)
= (+ 1 2)

Lists can be put into variables like any other Lisp object:

(setq x '(+ 1 2))

List elements can be any lisp object, including other lists. Here is a list with a number, a string, a list of numbers, a symbol, and a list, and a number:

(setq x '(1 "coucou" (4 5 6) asd (7 (8 9) 10) 20))

Here is another example where the same list as above is assembled from its members using the list function:

(setq x (list 1 "coucou" '(4 5 6) 'asd '(7 (8 9) 10) 20))

The first element (the head) of a list can be obtained with the car function, and the rest of the list (tail) with the cdr function (pronounced kudder). The cons function can be used to put a head and a tail together:

? (setq x '(+ 1 2))
= (+ 1 2)
? (car x)
= +
? (cdr x)
= (1 2)
? (setq z (cons '+ '(1 2)))
= (+ 1 2)

A list can be evaluated:

(setq x '(+ 1 2))
= (+ 1 2)
? (eval x)
= 3

Operations can be performed on all the elements of a list using the all construct:

? (setq z '(1 3 5 7 9))
= (1 3 5 7 9)
? (all ((x z)) (- x 1))
= (0 2 4 6 8)

This says, make a temporary variable x , and avaluate the body of the all with x set to each element of z in sequence. Then return a list of all the results.

This section only scratched the surface of what can be done with lists. The reader is referred to the List section in the "Core Interpreter" chapter of the Lush manual.



1.16. Strings and Regular Expressions


[under construction]



1.17. Scalars, Vectors, Matrices, Tensors, and Storages


Lush's piece de resistance is its matrix engine. Lush can operate on scalars, vectors, matrices, or high-dimensional tensors from 0 to 8 dimensions. creating a tensor of float is done simply with:
  ? (setq m (matrix 10 8 4))   ; create 3D matrix
  = ::INDEX3:<10x8x4>
  ? (m 3 4 2 45.6)       ; set value of element (3,4,2) to 45.6
  = ::INDEX3:<10x8x4>
  ? (m 3 4 2)            ; get value of element (3,4,2).
  = 45.6

Tensors of various basic types can be created with the functions listed below. Each function has two versions, the regular version initializes all the elements to zero, while the version with -nc at the end do not (no clear) and are a bit faster. All of these functions take 0 to 8 integer arguments that are the sizes in each dimension:

A matrix with 0 dimension is called a scalar. It is different from a regular number in that it behaves like a pointer to a number. (the value of a scalar passed as argument to a function can be modified by that function).

Matrices of doubles can be entered literally using square brackets:

  (setq m [[0 2 3 4][5 6 7 8]])
Matrices of other types can be specified by adjoining an apropriate character after the open bracket. Here is how to create a vector of floats:
  (setq m [f 0 2 3 4])
Characters f, i, s, b, u, a specify float, int, short, byte, ubyte, and atom respectively. Here is an example with atoms:
  (setq m [a "choucroute" "garnie"])

Matrices are really composed of two separate entities:



1.17.0. Working with Storages


srg and idx can be created independently of each other. So for example (setq s (double-storage 8)) creates a new storage of doubles with 8 elements. The call (double-storage) returns an unsized storage. Creating an idx on a particular storage s can be done with (new-index s '(3 4)) . This resizes the storage s to 12 elements (if it has less than that), and creates an idx of size (3, 4) on this storage. Creating other idxes on the same storage allows to access the same piece of data in multiple ways.

When directly accessing storage elements, storages behave like 1D idx (vectors). Storages can be created, allocated in memory, or memory-mapped to a file. Storage creation function are provided for the following types: doubles, floats, ints, shorts, bytes, unsigned bytes, generic pointers, and lisp object pointers.



1.17.1. Manipulating Tensors and IDX


Several functions are provided to create and manipulate the "idx" structure and its various fields.



1.17.2. Tensor Iterators


Lush provides efficient iterators to cycle over dimensions of a tensor. It is almost always better to use those iterators, rather than a regular loop with regular access to array elements because the latter method causes an array bound checking at each access, while the former doesn't. The main idx iterator is idx-bloop whose synopsis is as follows:
  (idx-bloop ((s1 idx1) [ (s2 idx2) [...(sn idxn) ]]) body)

Each si will be an idx with one less dimension than the corresponding idxi , and will simulataneously loop over the successive "slices" of idxi for each possible value of the first index. In other words, applying function myfunc to each element of a vector v1 and putting the result in the corresponding element in v2 can be done with:

  (idx-bloop ((x1 v1) (x2 v2)) (x2 (myfunc (x1))))

x1 and x2 are scalars (i.e. zero-dimensional tensors). The above function work just as well is v1 and v2 are n -dimensional tensors and myfunc accepts n-1 -th dimensional tensors as arguments. It should not be assumed that the multiple evaluations of the body are executed in sequence. They may be executed in parallel on some implementations of Lush. A similar function idx-eloop iterates on the last dimension of a tensor instead of the first dimension. For example, the matrix product operation C = A*B can be written as follows:

  (de idx-m2timesm2 (A B C) 
     (idx-eloop ((Bj B)(Cj C)) (idx-m2dotm1 A Bj Cj)))
where idx-m2dotm1 is the usual matrix-vector product. The idx-eloop construct simultaneously iterates over all columns of B and C (naturally, the function idx-m2timesm2 is predefined).

Another idx iterator allows to easily write the inner loop of a tensor operation in C, while leaving all the bookkeeping to the Lisp:

 (cidx-bloop (i_1 [i_2...i_n] (c_1 l_1) [(c_1 l_1)...(c_m l_m)) p_1 [p_2...])

This is somewhat equivalent to n nested idx-bloop s, which will simultaneously loop over the first n dimensions of idxs l_1 to l_m . The arguments i_1 to i_n are strings containing names of C local variables that will be set to the loop index in each of the n dimensions. At each iteration, the C variables provided in strings c_1 to c_m will point to the appropriate values in the idxs l_1 to l_m . For example, the following function will fill matrix a with cos(i+j).

    (de foo (a)
       ((-idx2- (-flt-)) a)
       (cidx-bloop ("i" "j" ("a" a)) #{ *a = cos(i+j); #}) a)

The return value is (like in idx-bloop) the last idx specified in the declaration (in the example above, the return value is superfluous).



1.17.3. IDX Manipulations


Several functions are provided to conveniently manipulate the idx structure itself. These functions do not manipulate the actual data (and therefore are efficient), they merely derive new idx from existing idx to access the data in new ways.

(narrow m n s [o]) returns a clone of idx m where the size in the n -th dimension is reduced to s elements, offset by o . This can be used to select bands or rectangular areas in matrices.

  ? (setq m [[0 2 3 4][5 6 7 8]])
  = [[ 0.00  2.00  3.00  4.00 ]
     [ 5.00  6.00  7.00  8.00 ]]
  ? (narrow m 1 2 1)
  = [[ 2.00  3.00 ]
     [ 6.00  7.00 ]]

(select m n s) return a clone of m , with the n -th dimension removed, and which is the s -th "slice" of m , in the n-th dimension. For example, the 3rd column of matrix m in the above example (which is a vector) can be obtained with

  ? (select m 1 2)
  = [ 3.00  7.00 ]

(unfold m n ksize step) returns an idx with an added dimension at the end of m obtained by "unfolding" n -th dimension. More explicitely, successive rows in the last dimension will contain successive, possibly overlapping, subsets of size ksize of consecutive elements in the n -th dimension. The separation between successive subsets is step . Here is an example:

  ? (setq m [0 1 2 3 4 5 6 7])
  = [ 0.00  1.00  2.00  3.00  4.00  5.00  6.00  7.00 ]
  ? (unfold m 0 3 1)
  = [[ 0.00  1.00  2.00 ]
     [ 1.00  2.00  3.00 ]
     [ 2.00  3.00  4.00 ]
     [ 3.00  4.00  5.00 ]
     [ 4.00  5.00  6.00 ]
     [ 5.00  6.00  7.00 ]]

No data is copied or replicated in the process, i.e., the three occurences of the number 2 in the above example actually come from a single memory location. The size of the new dimension is ksize . If dimn is the size of the n -th dimension of m , the size of the returned idx in the n -th dimension is (dimn-ksize)/step + 1 . The values of dimn , ksize , and step must be such that the new size is an integer.

The unfold function essentially allows to reduce a discrete convolution to a matrix-vector product. Here is an example:

  ? (setq m [1 1 0 2 3 4 2 0])
  = [ 1.00  1.00  0.00  2.00  3.00  4.00  2.00  0.00 ]
  ? (setq kernel [-1 2 -1])
  = [-1.00  2.00 -1.00 ]
  ? (setq output (matrix 6))
  = [ 0.00  0.00  0.00  0.00  0.00  0.00 ]
  ? (idx-m2dotm1 (unfold m 0 3 1) kernel output)
  = [ 1.00 -3.00  1.00  0.00  3.00  0.00 ]

A subsampled convolution can be implemented by unfolding with a step larger than 1:

  ? (setq m [0 1 2 3 4 5 6  7 8])
  = [ 0.00  1.00  2.00  3.00  4.00  5.00  6.00  7.00  8.00 ]
  ? (setq z (unfold m 0 3 2))
  = [[ 0.00  1.00  2.00 ]
     [ 2.00  3.00  4.00 ]
     [ 4.00  5.00  6.00 ]
     [ 6.00  7.00  8.00 ]]
  ? (setq kernel [1 2 1])
  = [ 1.00  2.00  1.00 ]
  ? (idx-m2dotm1 z kernel output)
  = [ 4.00 12.00 20.00 28.00 ]

Naturally, there is no real need for most programmers to use the unfold construct because the standard lush library contains efficient 1D and 2D convolutions .

(idx-transclone m dimlist) returns a clone of idx m where the dimensions have been permuted according to the list of dimension indices dimlist . For example (idx-transclone m '(0 2 1)) permutes the second and third dimensions (again, no data is moved or copied by this operations).

A few functions are provided to physically hack an idx to change a dimension, a modulo, or the offset (repectiveley (idx-changedim m n v), (idx-changemod m n v), (idx-changeoffset m n) ).



1.17.4. Simple Tensor Operations


Lush has lots of functions that operate on tensors of all types. These include component-wise unary operations (applying a function to all the elements of a tensor), such as abs, atan, clear, copy, cos, sin, exp, log, minus, sqrt,.... . They all take the form
 (idx-XXX m [r])

where XXX is one of the above function, m is the input matrix (from 0 to 8 dimensions) and r is an optional result matrix which must have the same dimensions as m . If r is not present, the result is created and returned.

Also available are component-wise dyadic operations such as add, sub, mul, div . They take the form

 (idx-XXX m1 m2 [r])

Next come dyadic operations where the second argument is a scalar, such as (idx-addm0 m s [r]) which adds scalar s to each element of tensor m , or (idx-addm0acc m s r) which does the same thing but accumulates the result in r , or (idx-dotm0 m1 s [r]) which multiplies each element of m by scalar s .



1.17.5. Operations between IDX and Scalars


Multiplying all the elements of an idx by a scalar can be done with:
  (idx-dotm0 m s [r])>
where m is an idx of any type and any number of dimensions, s is a scalar (i.e. an idx with zero dimension), and r is an optional idx in which the result will be written. Turning a number into a scalar can be performed with ((double-matrix) number ) . So for example, multiplying all the elements of a matrix by 10 is done as follows:
  ? (idx-dotm0 [1 2 3] ((double-matrix) 10))
  = [10.00 20.00 30.00 ]
Similarly, function idx-addm0 adds a scalar to all the elements of an idx.



1.17.6. Contracting Operations with Scalar Results


A number of functions are provided that take one or two input tensors and write the result in a scalar. Such functions include dot products, distances, sums of terms. They "contract" all the dimensions, i.e. the generalized dot product of two tensors is the sum of all the products of corresponding terms in the two tensors:
  (idx-dot m1 m2 [r])> 

Other such functions include idx-inf (smallest element), idx-sqrdist (sum of square difference between two tensor), idx-sum (sum of all terms), idx-sumsqr (sum of squares), idx-sup (largest element)



1.17.7. Special Inner and Outer Products


There are several functions for performing matrix-vector products, outer products, and such. They include: (idx-m1extm1 m1 m2 [r]) (outer product of vectors), (idx-m2dotm1 m v [r]) (matrix-vector multiply), (idx-m2extm2 m1 m2 [r]) (outer product of matrices which gives a 4D tensor), (idx-m4dotm2 m v [r]) (product of a 4D-tensor by a matrix where the last 2 dimension of the tensor are contract with the first two dimensions of the matrix). idx-m4dotm2 can be conveniently combined with appropriate calls to unfold to perform 2D convolutions, as demonstrated in the libary file lush/lsh/libidx/idx-convol.lsh .



1.17.8. Simple Linear Algebra


Lush provides a full interface to the Gnu Scientific Library as well as to BLAS and LAPACK, which contain all the linear algebra anyone could wish for. Using those functions directly may be a bit complicated, so lush provides a library with simple forms of the most common functions. This library can be loaded with (libload "libnum/linalgebra") . It contains the following functions:



1.18. Complex Numbers


Complex numbers in Lush are represented as (and totally equivalent to) vectors of doubles with 2 elements. Lush's complex numbers library is not automatically loaded at startup and should be loaded with:
  (libload "libnum/libcomplex")
Creating a complex number is done just like creating a vector of 2 doubles, or using the macro new-complex , which is equivalent to (double-matrix 2) :
  (setq z [3 4])            ; complex literal [real-part imaginary-part]
  (setq z (new-complex))    ; allocation of complex [0 0]
Complex vectors and matrices can be created with complex-matrix :
  (setq z (complex-matrix 3 3))
which is exactly equivalent to:
  (setq z (double-matrix 3 3 2))
Several complex arithmetics and functions are provided. The function names all begin with the letter c . Complex dyadic functions include c+, c-, c*, c/, c**, clogb (addition, subtraction, multiplication, division, power, complex log with complex base). All commonunary operations on complex are also provided, including conjugate, inverse, square root, exponential, log, and trigonometric functions. More details can be obtained in the packages/libnum section of the Lush manual ( "libnum: Numerical Library" ).

The memory layout of complex vectors and matrices so defined are compatible with the LAPACK and GSL functions that take double complex vectors and matrices as arguments.



1.19. Object-Oriented Lush Programming


Lush is an object-oriented language that allows users to define hierarchies of classes with inheritance, slots, and methods by deriving from the root class object .

Naturally, Lush has a number of built-in immutable classes such as numbers, list cells, strings, symbols, etc, to which users can add methods (but not slots). This section will concentrate on user-defined classes.



1.19.0. A New Class Definition


User defined classes are derived from the root class object with constructs like this:
  (defclass rectangle object width leng)
This can be interpreted as: define the class rectangle as a subclass of object with two slots width and leng . Subclasses inherit the slots of their superclass. (which is a moot point here since object has no slot).

A new instance of the class rectangle can be created with the function new :

  (setq r (new rectangle))
By default, the slots are left unfilled (set to the empty list). Accessing slots of an object can be done with the macro-character " : "
  ? (setq :r:width 10)
  = 10
  ? (setq :r:leng 3)
  = 3
  ? ^Pr
  ;;*** ::rectangle:819fa08, INSTANCE OF ::class:rectangle
  ;; FROM CLASS: rectangle
  ;;      width=10
  ;;      leng=3
  ;; FROM CLASS: object

Classes can be given methods (or virtual member functions in the C++ semantics) defined as in the following example:

  (defmethod rectangle area () (* leng width))
This defines the method area for the class rectangle which takes no argument, and returns the product of the slots leng and width . This is essentially similar to defining a function with de , except that within the body of a method, the slots of the object are directly accessible by name as if they were local variables. Calling the above method can be done as follows:
  ? (==> r area)
  = 30

which can be read as "send to r the message area ".

Methods can be passed arguments, and can refer to the current object through the special variable this . Here is an example of how to compute the volume of a box whose base is the current object and height is passed as argument:

  ? (defmethod rectangle volume (height) (* height (==> this area)))
  = volume
  ? (==> r volume 10)
  = 300



1.19.1. Inheritance


Lush allows to create subclasses of existing classes. Subclasses inherit the slots and methods of their parent class. For example, we can define a box class, derived from the rectangle class, and containing a height slot in addition the inherited width and leng :
  ? (defclass box rectangle height)
  = box
Setting the slots of an object directly as we did in the rectangle example is considered bad practice. A better alternative is to fill the slots when the object is created. This can be done by defining a constructor method. The constructor is a method that has the same name as the class. It is called whenever the new function is called to create an object of that class. Here is a constructor for box :
  ? (defmethod box box (l w h) (setq leng l) (setq width w) (setq height h))
  = box
  ?  (setq monolith (new box 9 4 1))
  = ::box:8138958
  ? ^Pmonolith
  ;;*** ::box:8138958, INSTANCE OF ::class:box
  ;; FROM CLASS: box
  ;;      height=1
  ;; FROM CLASS: rectangle
  ;;      width=4
  ;;      leng=9
  ;; FROM CLASS: object
  = ()
  ? (defmethod box volume () (* width leng height))
  = volume
  ? (==> monolith volume)
  = 36

An alternative way to define the volume method would have been to multiply the height by whatever result the area method inherited from rectangle returns:

  (defmethod box volume () (* height (==> this area)))
Class hierarchies are nice, but beginner should be careful not to create deep hierarchy trees with more than 3 or 4 levels of inheritance. Experience proves that deeper trees result in hard-to-maintain code.

Unlike C++, Lush neither support multiple inheritance, nor private slots and methods.



1.20. Input and Output


Lush offers several ways to exchange data with files, sockets, and other Lush processes.



1.20.0. Simple String Input/Output


The simplest way to print things is to use the printf function, which works pretty much like its C equivalent. The simplest way to read data into strings is done with read-string and skip-char , which are very flexible.

Normal output can be redirected to a file with the writing construct. For example, the code below will write 10 random integers to the file "blah":

  (writing "blah" (for (i 0 9) (printf "%d\n" (int (rand 0 100)))))

Similarly, input can be redirected from a file with the reading construct. For example, the code below will read the first line from text file "blah":

  (reading "blah" (read-string))

The first argument of reading and writing can be one of the following:

Here is an example of calling a pipe:
  (writing "| sort -n" (for (i 0 9) (printf "%d\n" (int (rand 0 100)))))



1.20.0.0. Filename Processing


Several functions allow manipulation of strings containing filenames and directories, such as (dirname "/asd/qwe.xxx") which returns the directory "/asd" ; and (basename "/asd/qwe.xxx") which returns the basename (without the directory) "qwe.xxx" ; (filename-get-suffixes "/asd/qwe.xxx") , which returns the filename extensions "xxx"; and (filename-chop-suffixes "/asd/qwe.xxx") , which removes the extensions "/asd/qwe".

The existence of a plain file "/asd/qwe.xxx" can be determined with (filep "/asd/qwe.xxx") , and the size of the file can be obtained with (file-size "/asd/qwe.xxx") (which returns nil if the file does not exist).

More sophisticated ways to examine the properties of a file are provided through the function fileinfo .



1.20.1. Complete File Reading


A number of functions are provided that make it easy to manipulate and process text files as a single entity (e.g. when writing shell scripts in Lush). Function (read-lines file) will return a list of strings, each of which contains one line of the file. Conversely, (write-lines f) will write a list of strings to a text file, with one line per string.



1.20.2. Lush Object Reading/Writing




1.20.2.0. Text File Reading


Lush text can be read from files using (read) . (read) will parse and read any Lush expression or atom (as is it were typed at the prompt) and return it. This allows to read lists, numbers and strings easily.

Conversely, printing Lush objects to a text file or on the terminal can be done with (print some-lush-object) .



1.20.2.1. Binary Serialization


One of the most powerful and convenient input/output capabilities of Lush is the ability to "serialize" (i.e. turn into a byte stream) any Lush object. This can be used to save and restore any Lush data struture to and from a file without having to worry about the file format. It can also be used by two Lush processes to communicate data (e.g. through a socket).

Saving a Lush object (say contained in variable some-lush-object ) to file "myfile.bin" can be done with:

  (writing "myfile.bin" (bwrite some-lush-object))
Restoring the object can be done with:
  (reading "myfile.bin" (setq some-lush-object (bread)))
Functions bread and bwrite stand for "binary read" and "binary write".



1.20.3. C-like stdio Functions


Another way to perform input/output is to call function from the standard C stdio library. Interfaces to a number of common functions are provided in libc/stdio.lsh . Functions include fopen , fclose , popen , pclose , ftell , fseek , fgetc , fputc , fgets , and various functions to read and write binary numbers into Lush variables.



1.20.4. Socket Communication


Lush provides a way to read from and write data to sockets using functions socketopen , socketaccept , and socketselect .

There is also a simple way to start another Lush process (on the same machine as the current process or on another one), and to send expressions to that remote process to be evaluated. This is implemented through the RemoteLush class. An instance of Lush must be running in "slave" mode on the remote machine; this is done by starting the script "lushslave".

See the documentation for "Remote Lush Execution" for more details.



1.21. Graphics


Lush offers several ways to output graphics. The most common one is the Lush graphic driver, which provides a small set of graphic primitive to display data in a window or write it to a PostScript file. Lush also provides interfaces to the OpenGL API and to the SDL API, but these will not be described in this section.

Opening a graphic window on the screen is simply done with:

  (new-window [<x> <y> [<w> <h> [<name>]]])
where the arguments are respectively the position, size and name of the new window.

Drawing in a window can be done with a collection of simple primitives:

Double-buffered and flicker-free redrawing can be done with the graphics-batch function. Used in the form (graphics-batch exp1 exp2 ... exp3) , it will evaluate all its argument, but any graphic operation performed in that time will be performed into an off-screen graphic buffer. This graphic buffer will be slapped on the window as the call to graphics-batch terminates. This allows smooth double-buffered animation:

 (while not-finished
   (compute-stuff)
   (graphics-batch 
      (draw-stuff-1)
      (draw-stuff-2)
      (draw-stuff-3)))

Here is an example:

 (libload "libimage/image-io")
 (setq m 
   (image-read-rgb 
     (concat-fname lushdir "packages/video4linux/demos/jabba-320x240.jpg")))
 (new-window)
 (for (i 0 99) (graphics-batch (cls) (rgb-draw-matrix i i m)))



1.21.0. Multiple Window Management


The function new-window provides a simply way to quickly open a graphic window on whatever graphic device is available (most likely your machine's X screen). Lush supports multiple windows under X, as well as "windows" (or graphic outputs) on other graphic devices. Opening two windows under X is done as follows:
  (setq win1 (x11-window 0 0 200 200 "Window 1"))
  (setq win2 (x11-window 0 220 200 200 "Window 2"))
Graphic commands occur in whatever window object is bound to the window symbol. So drawing a line into win2 can be done with:
  (let ((window win2)) (draw-line 10 10 100 100))
Closing a window is simply done by setting its handle to nil:
  (setq win1 ())



1.21.1. Editable Graphics via comdraw/ivtools Driver


A feature particularly useful to students and researchers is the ability to produce graphics that can be annotated and edited, so they can be included in papers and reports. Lush provides this capability through the comdraw graphic driver. comdraw is part of the ivtools package which can be obtained at http://www.ivtools.org/ivtools. Lush can send graphic command to comdraw. Comdraw graphics are immediately editable and can be exported to a number of formats, including an editable form of PostScript.

Opening a comdraw window is done with:

(setq window (comdraw-window x y width height))
Subsequent graphic commands will occur in the comdraw window. The function graphics-batch takes a new meaning in a comdraw window: it is used to group together the set of graphic objects created by the graphic commands called within the scope of the graphic-batch .



1.21.2. PostScript File Graphics


Although Lush can produce PostScript graphics (editable ones too) through the comdraw driver, it can also produce PostScript graphics directly. PostScript output is performed by opening a ps-window as follows:
(setq window (ps-window width height filename))
filename is the name of the PostScript file that will be generated.



1.22. Curve Plotting


Plotting curves can be done with the plotter class defined in the libplot/plotter library. Plotting can be performed in any type of window, including X11, PS, and comdraw. Creating a plotter is done with:
  (setq p (new plotter x y width height))
The plotter will attach itself to the current window, place its upper left hand corner at location x,y , and set its dimension in the window to width,height . A window will be automatically open if there is no current window. Using a plotter consists in adding "curves" to it and then calling the method "redisplay" to actually render it in the window to which it is attached.

Here is how to plot the log function in blue on the 0, 10 interval:

  (==> p PlotFunc "log" log 0 10 0.1 (alloccolor 0 0 1))
  (==> p redisplay)
Here is how to plot a segment of ellipse in red:
  (==> p PlotXY "lips" sin cos 0 5 0.1 (alloccolor 1 0 0))
  (==> p redisplay)
Here is how to plot a sparsely sampled green sinusoid (and indicating each sample by a filled circle):
  (setq x (range 0 10 0.5))
  (setq y (all ((v x)) (sin v)))
  (==> p plotlists "sine" x y (alloccolor 0 1 0) closed-circle)
  (==> p Redisplay)
A plotter can be moved or resize using the methods move and setsize :
  (setq p move 20 20)
  (setq p setsize 100 100)
  (==> p Redisplay)



1.23. Lush Executable Shell Scripts


Lush can be used to write executable scripts that can be invoked from the Unix prompt just like shell scripts, Perl scripts, or executable programs.

Rather than a long explanation, here is an example of a Lush script file:

  #!/bin/sh
  exec lush "$0" "$@"
  !#
  (printf "Capitalizing the arguments:\n")
  (each ((arg (cdr argv))) (printf "%s %s\n" arg (upcase arg)))
This works because Lush recognizes everything between #! and !# as a multi-line comment. This assumes that your lush executable is in your shell command search path.

In that mode, Lush does not display the usual startup banner. It load the standard environment ( sys/stdenv.dump or sys/stdenv.lsh ). It sets the variable argv to a list of strings, where the strings are the command line arguments (including the command itself). Finally it reads and evaluates the content of the script file. The script terminated when the evaluation of the last expression in the script returns or when the function exit is called.

The library libc/shell.lsh contains several functions to facilitate the writing of shell scripts. Among other things, it contains Lisp versions of common shell functions such as ls , cp , mv , etc.

Here is another script example: a photo slideshow program in 12 lines of Lush. Put this in a file (say lush-slideshow ), make it executable with chmod a+x lush-slideshow . Then, at the shell prompt, type: lush-slideshow photo1.jpg photo2.jpg photo3.jpg :

#!/bin/sh
exec lush "$0" "$@"
!#
(libload "libimage/image-io")
(libload "libimage/rgbaimage")
(setq window (x11-window 1 1 640 480 "Slide Show"))
(while t
  (each ((f (cdr argv)))
    (rgb-draw-matrix 
     0 0 (rgbaim-resize (image-read-rgba f) (xsize) (ysize) 0))
    (sleep 4)))



1.23.0. Executable GUI Applications


Writing a Lush scripts containing Ogre applications is a very good way to write executable GUI applications in Lush. Here is an example:
  #!/bin/sh
  exec $0
  !#
  ;; A simple Ogre GUI demo
  (ogre)
  (wait (new autowindowobject 10 10 100 100 "Simple Lush GUI Demo" 
          (new column
            (new stdbutton "    hit me    " (lambda (c) (printf "OUCH\n")))
           (new stdbutton "    feed me   " (lambda (c) (printf "CRUNCH\n"))))))
The wait function causes Lush to sit around and keep processing events until the argument of wait becomes nil (presumably as the result of processing an event). If we did not call wait in the above example, the script would terminate immediately after opening the Ogre window. The argument to wait is the WindowObject in which the Ogre application is set up. It is destroyed as soon as the user closes the window, hence terminating the script.



1.24. Lush Standalone Binary Executables


There is a somewhat crude facility that allows the generation of standalone executables from compiled Lush code. This can be useful for distributing Lush program to people who may not have installed Lush on their machine, or for integrating Lush-generated code into other C or C++ programs (or call Lush programs from any other program).

At this time, this is only possible for Lush functions that are fully compiled (no interpreted part is allowed).

This functionality is performed by the make-standalone function. the make-standalone function can generate a complete C source directory with all the supporting functions and macros to make a particular Lush function run.

The generated code can be redistributed with no restriction (it is not subject to the obligations of the GPL).

See the make-standalone documentation for more details.



1.25. Ogre GUI Toolkit


Lush contains a fairly complete Graphical User Interface toolkit built on top of the standard graphic library. Ogre allows very rapid development of GUI applications. An introduction and a tutorial are available in the Standard Library/Ogre section of this manual.
See: Introduction to Ogre.
See: Ogre Tutorial.
See: The Ogre Class Library.
Here we will just show a couple of very short examples of how simple GUIs can be created in just a few lines. First, here is the famous one-liner button "call a function when clicked":
  (ogre)
  (de coucou (c) (printf "coucou\n"))
  (new autowindowobject 10 10 () () "ouch" (new stdbutton "click me" coucou))

The autowindowobject is an ogre object that opens a new window and adjutst itself to fit the size of its content. In this case, the content is a single standard button (a.k.a. stdbutton ). The stdbutton constructor takes a string and a function with one argument which is called each time the button is pressed. Now, here is a slightly more sophisticated example:

 (ogre)
 (libload "libimage/image-io")
 (libload "libimage/rgbaimage")
 ;; load image
 (defvar image 
         (image-read-rgba 
           (concat-fname lushdir "packages/video4linux/demos/jabba-320x240.jpg")))
 ;; make an imageviewer object
 (setq image-viewer (new imageviewer 240 220 image t))
 ;; define a few functions to tell the imageviewer to display rotated images
 (de rot90-right (c) (==> image-viewer settext (rgbaim-rot90-right image)))
 (de rot00 (c) (==> image-viewer settext image))
 (de rot90-left (c) (==> image-viewer settext (rgbaim-rot90-left image)))
 ;; create the GUI window
 (new autowindowobject 10 10 () () "ouaf"
   ;; insert a column
   (new column
     ;; make a row of buttons
     (setq button-row
       (new row
         (new stdbutton "Left" rot90-left)        ; rotate left when clicked
         (new stdbutton "Straight" rot00)         ; straighten up when clicked
         (new stdbutton "Right" rot90-right)))     ; rotate right when clicked
     ;; insert imageviewer
     image-viewer))



1.26. Simple Directmedia Layer(SDL) Interface Usage


Lush includes an interface to the well-known SDL library (Simple Directmedia Layer), which has platform-independent functions for 2D graphics, timers, low-level keyboard, mouse, and joystick input, sound playing, direct read from CDROM, and many others features.

Lush provides a high-level interface to some of those functions in sdl/libsdl . It includes higher-level classes, such as screens and sprites, with pixel-accurate collision detection. This allows rapid development of graphic-intensive interactive applications such as real-time 2D games.

A tutorial on writing simple games with SDL is available in the Tutorial section of the Lush manual. A full documentation of the SDL interface is available at "SDL: Simple DirectMedia Layer"

The present section is a quick introduction to the libsdl library. Before you start, make sure SDL and all its development libraries and header files are installed on your system. If you are on Linux, those things are available as packages with your distro.

Loading and initializing the libsdl library is performed with:

  (libload "sdl/libsdl")
  (sdl-initialize)
Next, we can open an SDL screen. libsdl provides three kinds of SDL screen classes.



1.26.0. sdlidx-screen class: Mapping the Contents of an IDX to an SDL Screen


Let's start by describing the sdlidx-screen class. Opening an sdlidx-screen is done by first allocating a ubyte-matrix of size HxWx4, and then creating an sdlidx-screen with this matrix as argument. This will open an SDL screen of width W and height H:
  (setq depth 3)
  (setq m (ubyte-matrix 480 640 depth))
  (setq screen (new sdlidx-screen m "my title"))
If the depth parameter is 3, each element of matrix m is a component of an RGB pixel. So for example (m y x 0) is the R component of pixel (x, y) (from the top left of the screen). If the depth parameter is 4, each element of m is a component of an RGBA pixel. The A component is the Alpha channel (transparency). An alpha value of 255 is opaque, while 128 is half transparent. The matrix m can be seen as the "back buffer" of a double-buffered screen. Changing values in m will not immediately change the corresponding pixel on the screen. Once the desired RGBA image has been written in m , slapping it on the screen can be done with (==> screen flip) . If the screen was opened with depth =4, the image displayed will be an alpha-blended mixture of the previously displayed image and the content of m . Here is a complete example:
  (libload "sdl/libsdl")
  (libload "libimage/image-io")
  (libload "libimage/rgbaimage")
  (sdl-initialize)
  (setq m (ubyte-matrix 480 640 3))
  (setq screen (new sdlidx-screen m "my picture"))
  (setq photo (rgbaim-resize (image-read-rgba "mypicture.jpg") 640 480 0))
  (idx-copy (narrow photo 2 3 0) m)
  (==> screen flip)
Subsequent calls to (==> screen flip) will refresh the screen with the content of m . Note that SDL screens (unlike regular Lush graphic windows) are not automatically refreshed when uncovered from behind other windows. That is why SDL screens should be used only for animated graphics and games. Refresh rates on SDL screens are likely to be faster than with regular Lush graphic windows.



1.26.1. sdl-screen class: Doubled Buffered Animations


The sdl-screen class is intended for double-buffered animations using sprites (movable screen objects). This situation is primarily encountered when writing video games and other interactive multimedia applications.

Opening an sdl-screen is simply done with (setq screen (new sdl-screen 800 600 "the title")) . Drawing into an sdl-screen is made very simple by the sdl-sprite class (as explained below), but low-level SDL drawing can be performed by creating SDL_surface objects and calling SDL_BlitSurface on the p slot of the sdl-screen .



1.26.2. sdl-sprite: Movable Animated Objects


Interactive multimedia applications often involve drawing movable objects on the screen. This can be performed using Lush's sdl-sprite class, defined also in sdl/libsdl . Creating a sprite for drawing on the sdl-screen screen , and loading an image into it is done as follows:
  (setq sprite (new sdl-sprite screen 1))
  (==> sprite load-frame "mysprite.png" 0 0 0)
This creates a new sdl-sprite with id number 1 on screen screen , and loads frame 0 of this sprite with the image in file "mysprite.png" (the image can be in any format accepted by the SDL-image library dstributed with SDL). The three numerical arguments (all zeros in the example) are the frame number to be loaded, and the coordinates of the "handle" or "hot-point" of the sprite relative to the top-left corner.

Sprites can be moved around and drawn on the screen with:

  (==> sprite move x y)
  (==> sprite draw)
  (==> screen flip)
All drawing operations occur in the back buffer (not on the visible screen) until the call to (==> screen flip) .

The main loop of a typical application will look something like this:

  (while (not stop)
    [get user input, update coordinates, and such]
    (==> screen clear)
    (==> sprite1 move x1 y1)
    (==> sprite2 move x2 y2)
    (==> sprite1 draw)
    (==> sprite2 draw)
    (==> screen flip))
Sprites can have multiple frames. Switching between frames provides a mechanism for animating sprites. More details on how to write such applications (including reading keyboard events, animation and such) are given in the tutorial "Tutorial: Writing Games with Lush and SDL." . The code for that tutorial is available at .



1.26.3. sdlgl-screen class: OpenGL 3D Graphics in SDL Screens


The sdlgl-screen class is designed to allow OpenGL 3D graphics in an SDL screen. OpenGL graphics can be done in such an SDL screen, or can be done directly in GLUT windows. The sdlgl-screen should be used when SDL functionalities are used. Opening an sdlgl-screen can be done just like opening an sdl-screen :
  (setq screen (new sdlgl-screen 640 480 "my title"))
An example of use of sdlgl-screen is available at .



1.27. OpenGL Usage


Lush is also interfaced to OpenGL, and OpenRM which allows the development of 3D graphic applications.
See: OpenGL