SketchyLISP Reference |
Copyright (C) 2007 Nils M Holm |
[<<Summary] | [Contents] [Index] | [Syntax>>] |
Each SketchyLISP expression is a program and each program consists
of one or multiple expressions. Programs are executed
by
evaluating expressions:
(+ 2 3 4) => 9
Above line states that (+ 2 3 4)
evaluates to 9
. The lefthand side of the
=>
is an expression
and its righthandside is the normal
form (or the result
) of that expression.
The evaluates-to
arrow is not part of the language itself,
but it is used to denote the normal forms of expressions in texts
like this one.
SketchyLISP makes no difference between upper and lower case characters, but it folds all input to lower case.
There are multiple types of SketchyLISP forms or data:
The form ()
represents the
empty list, which is sometimes
also called nil.
Symbols, booleans, procedures, numbers, chars, and strings are called atoms or atomic forms, because they cannot be decomposed.
A symbol is represented by a name composed of these ASCII characters:
abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 * + - / < = > _ ? !
A pair is used to glue
two forms
together. Pairs look like this:
(x . y)
X and y may be forms of any type. The x part of a pair is also called its car part and the y part is called its cdr part part.
A list is a pair whose cdr part is
either another pair or ()
. The only exception is
the empty list which does not have a car nor a cdr part. Each list
of the form
(a1 . (a2 . ... (an . ()) ... ))
may also be written as
(a1 a2 ... an)
The second form is equivalent to the first one, but easier to read.
Lists whose last members are not equal to ()
are called improper lists.
Such lists have an atom in their last position. In improper lists,
the last element is separated using a dot:
(a b . c) = (a . (b . c)) (a b c . d) = (a . (b . (c . d)))
The boolean literal
#t
represents logical truth and
#f
represents logical falsity.
Note that #t
is merely the canonical form of the
true
value. Any form that is not identical to
#f
is considered true
.
Integer
numbers (or just integers
)
are represented by lists of digits with an optional leading plus or minus
sign, e.g.:
314 -159 +265
Integers are the only numbers in SketchyLISP, so the terms integer
and number
are exchangeable in this document.
Characters (or just chars
)
are introduced by the prefix #\
.
The character to be represented follows without any blanks in between, for
instance:
#\A #\b #\" #\\ #\# #\(
The blank character may be written as #\
, but for
improved readability, #\space
should be preferred.
#\newline
and #\linefeed
both represent
the ASCII linefeed (LF) character.
String are sequences of printable
characters (including blanks) which are delimited by double quotes
("
):
"abc" "Foo" "Hello, World!" "\"Hi,\" she said."
As shown above, quote characters may be included in strings by
escaping
them. A character is escaped
by prefixing it with a backslash (\
). To include the
backslash itself in a string, it must be escaped with another backslash:
"A \\ B"
Procedures are represented by lambda expressions of the form
(lambda (args) body)
They will be explained in detail in the following chapters.
At any point, a comment may be
placed in an expression by inserting a semicolon
(;
):
; this is a comment.
Each semicolon comment extends up to the end of the line it has been started in.
Besides semicolon comments, SketchyLISP accepts the following comments, which are to be expected in R6RS.
Like semicolon comments #!
comments extend to the end of the current line. They are useful for
running SketchyLISP programs as Unix scripts.
#! /usr/bin/sketchy -f
#|
and |#
are used to form nestable comments:
#| This is a commment #| containing a comment |# |#
#;
, finally, turns
a form into a comment. It is useful for commenting out
sub-expressions:
(+ 1 2 #;3 4) => 7 (+ (+ 2 3) #;(+ 3 4)) => 5
All characters are allowed in all comments except for form comments. Form comments must be valid forms. To the interpreter, a comment looks like a single space character.
The readable notation of a SketchyLISP datum is called its
external representation.
For example, 123
is the external representation of an
integer with the value 123 and "Hello, World!"
is the
external representation of a string containing the text
Hello, World!.
The external representation of a datum is the form that is used
to store that datum externally (i.e. outside of the interpreter).
The write
procedure writes the external representation
of a given form to the output stream. The read
procedures reads the external representation of a form and stores
it internally.
Most forms that can be written using write
have an
unambiguous external representation. When writing such a form and
then re-reading it, the original datum and the datum read are
guaranteed to be equal (but not identical). Form that do not have
unambiguous external representations cannot be re-read and hence cause
an error when a program attempts to read them.
Forms without an unambiguous external representation include procedures, the EOF object, and the void object. All these forms are represented using the following notation:
#<some informative text>
Here is a summary of all types of SketchyLISP forms including examples of their external representations:
foo symbol "some text" string 123 integer #\y char (foo . bar) pair (foo bar baz) pair (list) #t boolean #<procedure (x)> procedure #<primitive car> primitive procedure #<syntax lambda> keyword #<eof> end-of-file object #<void> void object
An expression is a form with a meaning. An expression evaluates while a form only exists. Forms are data, expressions are actions. Forms are used to build expressions:
(* 2 3 4)
is an expression that multiplies the values 2, 3, and 4. At the
same time it is a list containing the members *
,
2
, 3
, and 4
. Whenever the
interpreter encounters a form, it attempts to evaluate it, i.e.
it assumes that it is an expression.
Every expression is a form, but not all forms are expressions. For example
(if)
is a form (a list containing the symbol if
), but it
is not an expression, because if
expects a different
syntax. It is an error to try to evaluate a form that is not an
expression:
(if) => bottom
The symbol bottom
denotes that the form given before
the =>
has no normal form and hence cannot be
evaluated. The bottom value is contagious. Any expression that
contains a form that evaluates to bottom evalutes itself to bottom:
(+ 1 2 (if)) => bottom
Any expression can be turned into a datum by quoting it:
'(if) => (if)
The quote character turns the form that follows it into a datum.
The term datum
refers to a data object.
The term form
denotes an abstract entity that may
be either a datum or an expression, depending on its context.
The term expression
refers to a program that evaluates
to a value.
[<<Summary] | [Contents] [Index] | [Syntax>>] |