Introduction to newLISP/The basics

From Wikibooks, open books for an open world
Jump to: navigation, search

The basics[edit]

Downloading and installation[edit]

To download go to newLISP's home page, follow the download page link on the homepage. If you are using windows download the one called "newLISP v.10.4.0 GS-145 installer for Win32". Once it downloads run the installer, to install.

Getting started[edit]

Once you've installed newLISP, there are various ways to run it. See the newLISP documentation for full details. The most direct way is to run the newLISP interpreter from the command line - in a console or terminal window - by typing the newlisp command.

$ newlisp
newLISP v.x on OSX IPv4 UTF-8, execute 'newlisp -h' for more info.

>

This is good for trying out short expressions, testing ideas, and for debugging. You can write multi-line code in this environment by enclosing the lines between [cmd] and [/cmd]. In new versions you can simply use the enter key on a blank line to begin and also to end the multi-line block.

>[cmd]
(define (fibonacci n)
 (if (< n 2) 
  1
  (+ (fibonacci (- n 1))
     (fibonacci (- n 2)))))
[/cmd]
>(fibonacci 10)
89
>

The visual interface to newLISP, newLISP-GS, provides a graphical toolkit for newLISP applications, and it also gives you a development environment in which to write and test code: the newLISP editor. On Windows, this is installed as a desktop icon and a folder in the Program Start menu. On MacOS X, an application package and icon is installed in the Applications folder. The newLISP-GS editor provides you with multiple tabbed windows, syntax colouring, and a monitor area for seeing the results of running your code.

the newLISP-GS Editor

You can also run the newLISP-GS editor from the command line: you can find the file at C:/Program Files/newlisp/newlisp-edit (Windows), or at /usr/bin/newlisp-edit (on Unix). (This is a newLISP source file, so you can look at the code too.)

You can edit newLISP scripts in your favourite text editor. On MacOS X you can use BBEdit, TextWrangler, or TextMate to run newLISP scripts, or you can use one of the pre-installed Unix text editors such as vim or emacs. On Windows you can use UltraEdit, EditPlus, or NotePad++, to name just a few. If you use Linux, you know more about text editors than I do, and you probably already have a preference.

The newLISP web site hosts configuration files for a number of popular editors at http://newlisp.org/index.cgi?Code_Contributions.

On Unix, the first line of a newLISP script should be:

#!/usr/bin/newlisp

or:

#!/usr/bin/env newlisp

If you prefer to run newLISP in an external text editor, you have to use more println functions to see the value returned by every function or expression.

Generally, you end a newLISP script or a console session using the exit function:

(exit)

The three basic rules of newLISP[edit]

You have to learn just three basic rules to program in newLISP. Here's the first one:

Rule 1: a list is a sequence of elements[edit]

A list is a sequence of elements enclosed in parentheses:

(1 2 3 4 5)              ; a list of integers
("the" "cat" "sat")      ; a list of strings
(x y z foo bar)          ; a list of symbol names 
(sin cos tan atan)       ; a list of newLISP functions
(1 2 "stitch" x sin)     ; a mixed list
(1 2 (1 2 3) 3 4 )       ; a list with a list inside it
((1 2) (3 4) (5 6))      ; a list of lists

The list is the basic data structure in newLISP, and it's also the way you write your program code. But don't type these examples in just yet - there are two more rules to learn!

Rule 2: the first element in a list is special[edit]

When newLISP sees a list, it treats the first element as a function, and then tries to use the remaining elements as the information the function needs.

(+ 2 2)

This is a list of three elements: the function called +, followed by two numbers. When newLISP sees this list, it evaluates it and returns the value 4 (of course). Notice that the first element was treated by newLISP as a function, whereas the rest of the elements were interpreted as arguments to that function - numbers that the function expects.

Here are some more examples that demonstrate these first two rules:

(+ 1 2 3 4 5 6 7 8 9)

returns 45. The + function adds up all the numbers in the list.

(max 1 1.2 12.1 12.2 1.3 1.2 12.3)

returns 12.3, the biggest number in the list. Again, there's no (reasonable) limit to the length of the list: if a function is happy to accept 137 items (which both max and + are), than you can pass it 137 items.

(print "the sun has put his hat on")
"the sun has put his hat on"

prints the string of characters the sun has put his hat on. (It also returns the string, which is why, when you're working in the console, you sometimes see things repeated twice.) The print function can print out a single string of characters, or you can supply a sequence of elements to print:

(print 1 2 "buckle" "my" "shoe")
12bucklemyshoe

which prints the two numbers and the three strings (although not very well formatted, because you haven't met the format function yet).

The directory function:

(directory "/")

produces a listing of the specified directory, in this case the root directory, "/":

("." ".." ".DS_Store" ".hotfiles.btree" ".Spotlight-V100" 
".Trashes"".vol" ".VolumeIcon.icns" "Applications" 
"automount" "bin" "cores" "Desktop DB" "Desktop DF" 
"Desktop Folder" "dev""Developer" "etc" "Library" 
"mach" "mach.sym" "mach_kernel" "Network" "private" 
"sbin" "System" "System Folder" "TheVolumeSettingsFolder" 
"tmp" "User Guides And Information" "Users" "usr" 
"var" "Volumes")

It lists the current directory if you don't specify one:

(directory)
("." ".." "2008-calendar.lsp"  "allelements.lsp" "ansi.lsp" 
"binary-clock.lsp" ... )

There's a read-file function that reads in the contents of a text file:

(read-file "/usr/share/newlisp/modules/stat.lsp")

Here the function wants a single argument - the file name - and returns the contents of the file to you, in a string.

These are typical examples of the building blocks of newLISP code - a list containing a function call, followed perhaps by any extra information the function requires. There are over 380 newLISP functions, and you can refer to the excellent newLISP reference manual for details of all of them and how to use them.

You can try these examples. If you're using newLISP at a terminal, just type them in. If you're typing the lines into a text editor and running it as a script, you won't necessarily see the result of a function call unless you enclose the expression in the println function. For example, type:

(println (read-file "/usr/share/newlisp/modules/stat.lsp"))

to print the results of the read-file function.

Every newLISP expression returns a value. Even a println function returns a value. You could say that the printing action is actually just a side effect, and its main task is to return a value. You might notice that when you use println interactively in a console window, you see the return value twice: once when it's printed, and again when the value is returned to the calling function (the top-most level, in this case).

There's one more useful thing to look at before you meet the third rule.

Nested lists[edit]

You've already spotted one list nesting inside another. Here's another example:

(* (+ 1 2) (+ 3 4))

When newLISP sees this, it thinks as follows:

Hmm. Let's start with the first of those inner lists. I can do

(+ 1 2)

easily. The value of that is 3. I can also do the second list

(+ 3 4)

easily enough. That evaluates to 7.

So if I replace these two inner lists with these values, I get

(* 3 7)

which is really easy. I'll return the value 21 for this expression.

(* (+ 1 2) (+ 3 4))
(* 3 (+ 3 4))
(* 3 7)
21

See those two right parentheses at the end of the first line, after the 4? Both are essential: the first one finishes the (+ 3 4 list, and the second one finishes the multiplication operation that started with (*. When you start writing more complicated code, you'll find that you are putting lists inside lists inside lists inside lists, and you might be ending some of the more complicated definitions with half a dozen right parentheses. A good editor will help you keep track of them.

But you don't have to worry about white space, line terminators, various punctuation marks, or compulsory indentation. And because all your data and your code are stored in the same way, in lists, you can mix them freely. More on that later.

Some people worry about the proliferation of parentheses when they first see LISP code. Others refer to them as nail clippings or say that LISP stands for Lots of Irritating Silly Parentheses. But I prefer to think of the parentheses as small handles that enclose a newLISP thought:

grabbing the handles of a newLISP thought

When you're editing newLISP code in a good editor, you can easily move or edit a thought by grabbing its handles, and easily select a thought with a Balance Parentheses command. You'll soon find the parentheses more useful than you first thought!

Quoting prevents evaluation[edit]

You can now meet the third rule of programming with newLISP:

Rule 3: Quoting prevents evaluating[edit]

To stop newLISP evaluating something, quote it.

Compare these two lines:

(+ 2 2)
'(+ 2 2)

The first line is a list which contains a function and two numbers. In the second line, the list is quoted - preceded by a single quote or apostrophe ('). You don't need to put another quote at the end, after the closing parenthesis, because one is sufficient.

> (+ 2 2)
4
> '(+ 2 2)
(+ 2 2)
>

For the first expression, newLISP does its job as usual, and enthusiastically evaluates the list, returning the number 4. But for the second expression, as soon as it sees the quotation mark, newLISP doesn't even think about evaluating the list by adding the numbers; it just returns the list, unevaluated.

This quotation mark does the same job in newLISP that opening and closing quotation marks do in written English - they inform the reader that the word or phrase is not to be interpreted normally, but treated specially in some way: a non-standard or ironic meaning, perhaps, something spoken by another person, or something not to be taken literally.

So why do you want to stop newLISP evaluating things? You'll soon meet some examples where you quote things to prevent newLISP thinking that the first item in a list is a function. For example, when you store information in a list, you don't want newLISP to evaluate them in the usual way:

(2006 1 12)                 ; today's year/month/date
("Arthur" "J" "Chopin")     ; someone's full name

You don't want newLISP to look for functions called 2006 or "Arthur". Besides, 2006 isn't a valid function name, because it starts with a digit, and function names can't start with a double quotation mark, so in either case your program will stop with an error. Therefore you quote the lists to stop their first elements being used as functions rather than data:

'(2006 1 12)                 ; evaluates to (2006 1 12)
'("Arthur" "J" "Chopin")     ; evaluates to ("Arthur" "J" "Chopin")

newLISP's ability to treat expressions as data - and data as expressions - is discussed in more detail later.

Use the vertical apostrophe (ASCII code 39) to quote lists and symbols. Sometimes, text editors or other programs change these simple vertical apostrophes into curly quotation marks. These don't do the same job, so you will have to change any smart quotes to vertical apostrophes.

Symbols and quotes[edit]

A symbol is a newLISP thing with a name. You define something in your code and assign a name to it. Then you can refer to that something later on, using the name rather than the contents. For example, after typing this:

(set 'alphabet "abcdefghijklmnopqrstuvwxyz")

there's now a new symbol called alphabet whose value is a string consisting of the 26 letters of the alphabet. The set function stores the string of characters from a to z in the symbol alphabet. Now this symbol can be used elsewhere, and will evaluate to the alphabet whenever it's used. Whenever you want to use the 26 letters of the alphabet, you use this symbol without quoting it. For example, here's the upper-case function:

(upper-case alphabet)
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"

I use the symbol without quoting it, because I want newLISP to use the value of the symbol, not its name. I'm really not interested in upper-casing the word alphabet, but the alphabet itself. newLISP hasn't permanently changed the value of the symbol, in this example, because upper-case always creates and returns a new string, leaving the one stored in the symbol unchanged.

Symbols correspond to variables in other programming languages. In fact, newLISP doesn't use symbols quite as much as other languages use variables. This is partly because values are continually being returned by expressions and fed directly into other expressions without being stored. For example, in the following code each function hands its result directly to the next, enclosing function:

(println (first (upper-case alphabet)))
"A"

upper-case gives its return value directly to first, which gives its return value directly to println, which both prints it and gives you the string it printed as the return value. So there's less need to store values temporarily. But there are plenty of other places where you do want symbols.

Here are two more examples of symbol-quoting:

(define x (+ 2 2 ))
(define y '(+ 2 2))

In the first example, I don't quote the (+ 2 2) list - newLISP evaluates this to 4 and then assigns 4 to the symbol x, which evaluates to 4:

x
;-> 4

In the second example I quote the list. This means that the symbol y is now holding a list rather than a number. Whenever newLISP sees the symbol y, it will return the list, rather than 4. (Unless, of course, you quote y first as well!)

y
;-> (+ 2 2)
'y
;-> y

By the way, throughout this document:

; the semicolon is the comment character
;-> that ";->" is my way of saying "the value is"

and output printed by the newLISP interpreter is usually shown

like this

Setting and defining symbols[edit]

There are various ways to create and set the value of symbols. You can use define or set, as follows:

(set 'x (+ 2 2))
;-> 4
(define y (+ 2 2))
;-> 4

set expects to be followed by a symbol, but evaluates its first argument first. So you should either quote a symbol to prevent it being evaluated (because it might evaluate to something other than a symbol), or supply an expression that evaluates to a symbol. define doesn't expect the argument to be quoted.

You can also use setf and setq to set the value of symbols. These expect a symbol or a symbol reference as the first argument, so you don't have to quote it.

(setf y (+ 2 2))
;-> 4
(setq y (+ 2 2))
;-> 4

These two functions (which have the same action) can set the contents of a symbol (variable), a list, an array, or a string. A convention is to use setq when setting a symbol, and setf when setting an element of a list or array.

define is also used to define functions. See Make your own functions.

Destructive functions[edit]

Some newLISP functions modify the values of the symbols that they operate on, others create a copy of the value and return that. Technically, the ones that modify the contents of symbols are described as destructive functions - although you'll often be using them to create new data. In this document I'll describe functions such as push and replace as destructive. This simply means that they change the value of something rather than return a modified copy.