SketchyLISP Reference |
Copyright (C) 2007 Nils M Holm |
[<<Syntax] | [Contents] [Index] | [Syntax Transformation>>] |
4.1 Introduction
4.2 Bindings and Definitions
4.3 Control
4.4 Composition and Decomposition
4.5 Predicates
4.6 Type Conversion
4.7 Char Procedures
4.8 Numeric Procedures
4.9 String Procedures
4.10 Vector Procedures
4.11 Input/Output
This chapter summarizes the primitive procedures of SketchyLISP. Another large part of SketchyLISP consists of user-level procedures, which are described in a later chapter.
Primitive procedures are procedures that are not implemented using lambda expressions for a variety of reasons. The decision whether a procedure is primitive or not is eventually part of the implementation strategy. Other implementations may chose other sets of primitives.
SketchyLISP primitives perform simple task (like composing or decomposing pairs) as well as potentially computation-intensive tasks (such as adding big numbers or appending strings).
At the beginning of each procedure description a generalized sample application is given. This application lists the types that the procedure expects by giving examples:
(car '(x . y)) => x
Unless such an example uses a variable as argument, it is an error to apply the procedure to a type other than that specified in the example:
(car 'non-pair) => bottom
When a variable is used as an argument, the procedure accepts any type:
(pair? x) => {#t,#f}
The symbol bottom
is used to denote an
undefined
value. A value is
undefined, if it does not have
a unique normal form. This does not imply that
a reduction that results in bottom
terminates
with an error. It rather says that the result of the reduction
should be considered invalid.
As an example, consider the expression
(eq? 1 1)
which may reduce to #t
or #f
,
since the identity of numbers is arguable. Because the result is not
predictable, it must be considered undefined:
(eq? 1 1) => bottom
(bottom ...) => bottom
Applications of bottom
evaluate to an undefined
result. Any expression that contains a subexpression evaluating to
(bottom)
evaluates itself to (bottom)
.
The bottom
procedure may have any number of arguments.
(bottom) => bottom (bottom 'x 'y 'z) => bottom (eq? (bottom) ()) => bottom
The bottom
procedure is a SketchyLISP Extension.
(gensym [symbol]) => symbol
Gensym
returns a unique symbol each time it is
applied. The symbol is guaranteed not to have occurred anywhere
in the calling program. From this follows that gensym
returns different symbols when it is called multiple times:
(gensym) => gensym1 (gensym) => gensym2 (gensym) => gensym3
When a symbol is passed to gensym
, this symbol will
be a prefix of the new symbol:
(gensym 'foo) => foo4 (gensym 'x) => x5
When no prefix is given, gensym is used.
The gensym
procedure is a SketchyLISP Extension.
(load "file") => #<void>
Loads
loads a file by reading its definitions and
reducing them to their normal forms. Normal forms are not echoed.
If the file name passed to load
begins with a dot
(.) or a slash (/) or a tilde (~),
load
simply attempts to open that file. Otherwise the
following locations are tried:
The SKETCHYSRC environment variable is a colon-separated
list of paths. Load
tries the given file name (with and
without the .scm suffix) in all directories specified in this
variable before giving up.
To see which file load
actually loads, use the
:load meta command.
If a file that is being loaded by load
loads
other files, the files loaded by nested applications will be
searched in the directory of the original file first. Here is
an example:
(load "lib/foo.scm")
will load the file foo.scm from the directory lib, so all files loaded by foo.scm will be searched inside of lib first. Hence the command
(load "bar.scm")
inside of lib/foo.scm will load lib/bar.scm if that file exists. Only if lib/bar.scm does not exist, other locations will be tried.
Load
resolves path names beginning with a
~/ prefix by replacing the ~ of
that prefix with the value of the HOME environment
variable.
The load
procedure conforms to R5RS with one extension:
(package ['symbol]) => symbol
The package
procedure is used to protect
global symbols from re-definition. The symbols to be protected
(which are typically created using define
) are enclosed
in two applications of package
. The first application
creates a new package which is to contain the protected symbols.
The second one closes the package. An opening application names the
package using its argument. Closing applications have no arguments.
When multiple packages define equal symbols, the currently open package is always searched first. The order of searching the other packages is unspecified. When no user-defined package is open, an initial package called the default package is open.
The following program demonstrates the use of package
:
(define foo #t) ; protect package (package 'foo) ; create and/or open package foo (define bar 'baz) (define (f) bar) (package) ; close package foo (f) => baz (define bar 'goo) ; re-define bar bar => goo ; bar is re-defined as expected (f) => baz ; f of foo still returns bar of foo
Caveats
Packages break the identity of symbols:
(package 'p) (define (f) 'unique-name) (package) (define unique-name #t) (f) => 'unique-name (eq? 'unique-name (f)) => #f
There is normally no need to use package
in user-level
code. It was added to protect some internal procedures of the SketchyLISP
implementation from re-definition.
The package
procedure is a SketchyLISP Extension.
(recursive-bind env) => env
The recursive-bind
procedure is used by the
letrec
syntax to fix references to recursive
procedures in local environments.
The environment passed to recursive-bind
is an
association list (a list of pairs) with procedure names as keys
(car parts) and procedures as values (cdr parts):
((f . #<procedure () (f) ((f . #<void>))>))
The above association list associates a recursive zero-argument
procedure with the symbol f. Such an association is
typically created by the let
syntax. Because
let
binds the procedure to its name after
closing over the name, the procedure cannot recurse:
(f) => bottom
Any application of f in f results in an application of a non-procedure.
To make the recursive procedure f work, the binding of
f in the lexical environment of f must
be bound to the value of f in the outer environment
- the environment passed to recursive-bind
. In other
words: the local definition of f must bind to f
itself. This is exactly what recursive-bind
achieves:
(recursive-bind '((f . #<procedure () (f) ((f . #<void>))>))) => ((f . #<procedure () (f) ((f . #<procedure () (f) ((f . ...))>))>))
Recursive-bind
resolves mutually recursive defintions
as well.
Notes
The structure created by recursive-bind
is potentially
self-referential and hence infinite. Do not try to print it.
The creation of recursive bindings is normally done using
letrec
. Recursive-bind
is a conceptual
procedure that serves no other purpose than facilitating the
implementation of metacircular interpreters.
The recursive-bind
procedure is a SketchyLISP Extension.
(require "file") => {#t,#f}
Require
loads a package (using load
)
that is required by the program or package following in the input
stream. It reads definitions from the given file and reduces them
to their normal forms. Normal forms are not echoed.
Require
reads the package only if it has not been
required before. It returns #t
after actually reading
a package and #f
when the package already was present.
To determine whether a package already has been required,
require
tests whether the basename of the given file
is a symbol that is bound to a value. The
basename is the name of the given
file with its directory and suffix removed:
(require "src/unlet.scm") ; "unlet" is the basename
The require
procedure is a SketchyLISP Extension.
(void) => #<void>
The void
procedure evaluates to an unspecific value:
(void) => #<void>
The void
procedure is a SketchyLISP Extension.
(apply fun a1 ... an list) => eval[(fun a1 ... an . list)]
Apply
applies the procedure fun to the
arguments contained in the list list. The additional
arguments a1...an are
optional. All arguments are passed to apply
call-by-value,
but fun is applied to the arguments in list
using call-by-name. The number of arguments of fun (plus
n, if additional arguments are given) must match the number
of members of list. For example,
(apply cons '(a b)) => (a . b) (apply (lambda () 'foo) '()) => foo (apply cons '(a)) => bottom
If any additional arguments a1...an are specified, these are consed to the argument list list before applying fun to it:
(apply cons 1 '(2)) => (1 . 2) (apply list 1 2 3 '(4 5)) => (1 2 3 4 5)
The apply
procedure conforms to R5RS.
(car '(x . y)) => x
(Car x)
evaluates to the car part of
x. X must be a pair. The following
rules apply:
(car '(x . y)) => x (car '(x y)) => x (car '(x)) => x (car ()) => bottom (car 'non-pair) => bottom
The car
procedure conforms to R5RS.
(cdr '(x . y)) => y
(Cdr x)
evaluates to the cdr part of
x. X must be a pair. The following
rules apply:
(cdr '(x . y)) => y (cdr '(x y)) => (y) (cdr '(x)) => () (cdr ()) => bottom (cdr 'non-pair) => bottom
The cdr
procedure conforms to R5RS.
(cons 'x 'y) => (x . y)
Cons
creates a new pair from two given forms.
Its first argument x forms the car part of the new pair
and its second argument y forms its cdr part. The
following rules apply:
(cons 'x 'y) => (x . y) (cons 'x ()) => (x) (cons 'x '(y . ())) => (x y) (cons 'x '(y)) => (x y) (cons 'x '(y . z)) => (x y . z)
The cons
procedure conforms to R5RS.
(char? x) => {#t,#f}
(Char? x)
evaluates to #t
if x is a char and otherwise to #f
.
The following rules apply:
(char? #\x) => #t (char? #\space) => #t (char? #\\) => #t (char? 'non-char) => #f
The char?
procedure conforms to R5RS.
(eq? x y) => {#t,#f}
(Eq? x y)
evaluates to #t
if
x and y are identical and otherwise
to #f
. Two forms are identical, if, and only if
they are the same symbol or they are both the same boolean or
they are both empty lists. All other forms may be different, even
if they look equal. Forms bound to the same symbol are always
identical, so
(eq? a a) => #t ; unless A is not bound
for any value of a. The following rules apply:
(eq? x x) => #t (eq? 'x 'x) => #t (eq? 'x 'y) => #f (eq? () ()) => #t (eq? 'x '(x . y)) => #f (eq? #f #f) => #t (eq? '(x y) '(x y)) => bottom (eq? 123 123) => bottom (eq? #\x #\x) => bottom (eq? "foo" "foo") => bottom
Note especially that:
(eq? (cons x y) (cons x y)) => #f
for any values of x and y.
The eq?
procedure conforms to R5RS.
(null? x) => {#t,#f}
(Null? x)
evaluates to #t
if x is equal to ()
and otherwise
to #f
.
The null?
procedure conforms to R5RS.
(number? x) => {#t,#f}
(Number? x)
evaluates to #t
if x is a number and otherwise to #f
.
The following rules apply:
(number? 123) => #t (number? -123) => #t (number? +123) => #t (number? 'non-integer) => #f
The number?
procedure conforms to R5RS.
(pair? x) => {#t,#f}
Applications of pair?
evaluate to
#t
if x is a pair and otherwise to
#f
. The following rules apply:
(pair? '(x . y)) => #t (pair? '(x y)) => #t (pair? ()) => #f (pair? 'non-pair) => #f
The pair?
procedure conforms to R5RS.
(procedure? x) => {#t,#f}
(Procedure? x)
evaluates to #t
if x is a procedure and otherwise to #f
.
The following objects are procedures:
lambda
The following rules apply:
(procedure? cons) => #t (procedure? procedure?) => #t (procedure? lambda) => #f (procedure? (lambda (x) x)) => #t (procedure? 'non-procedure) => #f
The procedure?
procedure conforms to R5RS.
(string? x) => {#t,#f}
(String? x)
evaluates to #t
if x is a string and otherwise to #f
.
The following rules apply:
(string? "some text") => #t (string? "") => #t (string? 'non-string) => #f
The string?
procedure conforms to R5RS.
(symbol? x) => {#t,#f}
(Symbol? x)
evaluates to #t
if x is a symbol and otherwise to #f
.
The following rules apply:
(symbol? 'foo) => #t (symbol? 'symbol?) => #t (symbol? symbol?) => #f (symbol? "non-symbol") => #f
The symbol?
procedure conforms to R5RS.
(vector? x) => {#t,#f}
(Vector? x)
evaluates to #t
if x is a vector and otherwise to #f
.
The following rules apply:
(vector? #(1 2 3)) => #t (vector? #()) => #t (vector? 'non-vector) => #f
The symbol?
procedure conforms to R5RS.
(char->integer #\c) => integer
The char->integer
procedure evaluates to an integer
whose value is equal to the ASCII code of its argument.
The following rules apply:
(char->integer #\a) => 97 (char->integer #\A) => 65 (char->integer #\space) => 32 (char->integer #\\) => 92 (char->integer 'non-char) => bottom
The char->integer
procedure conforms to R5RS.
(integer->char 123) => char
The integer->char
procedure evaluates to a char
whose ASCII code is equal to its argument. The argument must be in
the range 0..127. The following rules apply:
(integer->char 97) => #\a (integer->char 65) => #\A (integer->char 32) => #\space (integer->char 92) => #\\ (integer->char 'non-integer) => bottom (integer->char -1) => bottom (integer->char 128) => bottom
The integer->char
procedure conforms to R5RS.
(integer->list 123) => list
The integer->list
procedure evaluates to a list
containing the digits and, if one exists, the prefix of the given
integer. Digits are represented by the symbols
0d
through 9d
.
The following rules apply:
(integer->list 0) => (0d) (integer->list 123) => (1d 2d 3d) (integer->list -5) => (- 5d) (integer->list +7) => (+ 7d) (integer->list 'non-integer) => bottom
The integer->list
procedure is a SketchyLISP Extension.
(list->integer list) => integer
The list->integer
procedure evaluates to an
integer composed of the digits and the prefix (if any) contained
in the given list. The list must contain a positive number of digits,
and it may contain a sign of the form +
or -
at its first position. Digits are represented by the symbols
0d
through 9d
.
The following rules apply:
(list->integer '(0d)) => 0 (list->integer '(1d 2d 3d)) => 123 (list->integer '(- 7d)) => -7 (list->integer '(+ 5d)) => +5 (list->integer '(non-digit)) => bottom (list->integer '()) => bottom (list->integer '(-)) => bottom (list->integer '(+ + 1d)) => bottom (list->integer 'non-list) => bottom
The list->integer
procedure is a SketchyLISP Extension.
(list->string list) => string
The list->string
procedure evaluates to a string
that is composed of the characters contained in the list passed to it.
The list must contain objects of the type char exclusively.
The following rules apply:
(list->string '(#\X)) => "X" (list->string '(#\t #\e #\x #\t)) => "text" (list->string '()) => "" (list->string '(#\")) => "\"" (list->string '(non-char)) => bottom (list->string 'non-list) => bottom
The list->string
procedure conforms to R5RS.
(list->vector list) => vector
The list->vector
procedure evaluates to a vector
that is composed of the forms contained in the list passed to it.
The following rules apply:
(list->vector '(foo)) => #(foo) (list->vector '(1 2 3 4)) => #(1 2 3 4) (list->vector '()) => #() (list->vector 'non-list) => bottom
The list->vector
procedure conforms to R5RS.
(string->list "xyz") => list
The string->list
procedure evaluates to a list
containing the same characters as the string passed to it. Each
character of the string will be represented by an individual char
in the resulting list. The following rules apply:
(string->list "X") => (#\X) (string->list "text") => (#\t #\e #\x #\t) (string->list "") => () (string->list "\"") => (#\") (string->list 'non-string) => bottom
The string->list
procedure conforms to R5RS.
(string->symbol "xyz") => xyz
The string->symbol
procedure evaluates to a symbol
that is composed of the characters of the given string argument.
The following rules apply:
(string->symbol "foo") => foo (string->symbol "FOO") => FOO (string->symbol " ") => #<unreadable symbol> (string->symbol "") => bottom (string->symbol 'non-string) => bottom
Notes
(1) String->symbol
may be used to create symbols that
cannot be accessed by programs, such as symbols containing white space,
symbols containing upper case letters, and symbols containing special
characters like parentheses, dots, semicolons, etc.
(2) Symbols containing spaces lead to an ambiguity, as demonstrated below. Therefore future implementation of SketchyLISP may refuse to create such symbols.
(string->symbol "foo bar") => foo bar (symbol->string (string->symbol "foo bar")) => "foo bar" (symbol->string 'foo bar) => bottom
The string->symbol
procedure conforms to R5RS with
one restriction:
string->symbol
allows the creation of empty
symbols.(symbol->string 'xyz) => "xyz"
The symbol->string
procedure evaluates to a string
that is composed of the characters of the symbol passed to it.
The following rules apply:
(symbol->string 'foo) => "foo" (symbol->string 'FOO) => "foo" (symbol->string "non-symbol") => bottom
The symbol->string
procedure conforms to R5RS.
(vector->list vector) => list
The vector->list
procedure evaluates to a list
containing the same forms as the vector passed to it. The following
rules apply:
(vector->list '(foo)) => (foo) (vector->list '(1 2 3 4)) => (1 2 3 4) (vector->list #()) => () (vector->list 'non-vector) => bottom
The vector->list
procedure conforms to R5RS.
(char-ci<? #\a #\B ...) => {#t,#f} (char-ci<=? #\c #\C ...) => {#t,#f} (char-ci=? #\c #\C ...) => {#t,#f} (char-ci>? #\B #\a ...) => {#t,#f} (char-ci>=? #\C #\c ...) => {#t,#f}
The char-ci...?
procedures test whether a given
monotonic ordering applies to their arguments. They return
#t
, if the ordering applies and otherwise #f
.
The char-ci...?
procedures are case-insensitive.
The following rules apply:
(char-ci<? #\a #\b) => #t (char-ci<=? #\a #\A) => #t (char-ci=? #\A #\a) => #t (char-ci>? #\B #\a) => #t (char-ci>=? #\B #\b) => #t (char-ci<? #\a #\b #\c) => #t (char-ci<? #\b #\a) => #f (char-ci=? 'non-char #\x) => bottom (char-ci=? #\x 'non-char) => bottom
The char-ci<?
, char-ci<=?
,
char-ci=?
, char-ci>?
, and
char-ci>=?
procedures conform to R5RS.
(char<? #\a #\b ...) => {#t,#f} (char<=? #\c #\c ...) => {#t,#f} (char=? #\c #\c ...) => {#t,#f} (char>? #\b #\a ...) => {#t,#f} (char>=? #\c #\c ...) => {#t,#f}
The char...?
procedures test whether a given
monotonic ordering applies to their arguments. They return
#t
, if the ordering applies and otherwise #f
.
The following rules apply:
(char<? #\a #\b) => #t (char<=? #\a #\a) => #t (char=? #\a #\a) => #t (char>? #\b #\a) => #t (char>=? #\b #\b) => #t (char<? #\a #\b #\c) => #t (char<? #\b #\a) => #f (char=? 'non-char #\x) => bottom (char=? #\x 'non-char) => bottom
The char<?
, char<=?
,
char=?
, char>?
, and
char>=?
procedures conform to R5RS.
(n+ num1 num2) => num3
The n+
procedure adds two natural numbers
num1 and num2 (no signs
are allowed!) and returns their sum num3.
Precision is arbitrary, no overflow can occur.
N+
is used to implement the more general bignum
arithmetic procedure like +
, *
, etc.
The following rules apply:
(n+ 12 9) => 21 (n+ 12 0) => 12 (n+ 12 +1) => bottom (n+ -12 1) => bottom (n+ 'non-number 123) => bottom (n+ 123 'non-number) => bottom
The n+
procedure is a SketchyLISP Extension.
(n- num1 num2) => num3
The n-
procedure subtracts the number
num2 from num1, returning
their difference num3. Both of its arguments must
be natural numbers without any signs. N-
cannot
create negative results, so num2 must be less
than or equal to num1. This procedure may subtract
number of any size.
N-
is used to implement the more general bignum
arithmetic procedure like +
, *
, etc.
The following rules apply:
(n- 12 9) => 3 (n- 12 0) => 12 (n- 9 12) => bottom (n- 12 +1) => bottom (n- -12 1) => bottom (n- 'non-number 123) => bottom (n- 123 'non-number) => bottom
The n-
procedure is a SketchyLISP Extension.
(n< num1 num2) => {#t,#f}
The n<
procedure compares the two natural
numbers num1 and num2,
returning #t
if num1 is less than
num2. In case num1 is
greater than or equal to num2, it returns
#f
. N<
may compare number of any size.
The n<
procedure is used to implement the more general
bignum comparison procedure like <
, >=
, etc.
The following rules apply:
(n< 9 12) => #t (n< 12 9) => #f (n< 12 +9) => bottom (n< -12 9) => bottom (n< 'non-number 123) => bottom (n< 123 'non-number) => bottom
The n<
procedure is a SketchyLISP Extension.
(read-from-string string) => {(form), #f}
Read-from-string
reads the external representation of
a form from the given string, converts it to internal representation, and
returns a singleton list containing that form. Read
is capable
of reading any unambiguous external representation that was written by
write-to-string
.
Read-from-string
expects that the input string
terminates after the form read. In case there are trailing characters
after the expression, it returns #f
.
In case the input string does not contain a well-formed datum,
read-from-string
returns #f
.
Read-from-string
skips over all sorts of comments
found in its input.
Here are some sample applications of read
:
(read-from-string "foo") => (foo) (read-from-string " foo") => (foo) (read-from-string "'foo") => ('foo) (read-from-string "\"hello\"") => ("hello") (read-from-string "#\\x") => (#\x) (read-from-string "#\\space") => (#\space) (read-from-string "#\\;") => (#\;) (read-from-string "#f") => (#f) (read-from-string "(x . y)") => ((x . y)) (read-from-string "#|...|# x") => (x) (read-from-string "foo bar") => #f (read-from-string "(x") => #f (read-from-string "") => #f (read-from-string "#<foo>") => #f
The read-from-string
procedure is a SketchyLISP extension.
(string-append str1 ...) => str
String-append
returns a new string that contains the
concatenation of the strings passed to it as arguments. The following
rules apply:
(string-append) => "" (string-append "xyz") => "xyz" (string-append "x" "y" "z") => "xyz" (string-append 'non-string) => bottom
The string-append
procedure conforms to R5RS.
(string-length str) => num
The string-length
procedure returns the number of
characters contained in the string str. The following rules
apply:
(string-length "") => 0 (string-length "xyz") => 3 (string-length 'non-string) => bottom
The string-length
procedure conforms to R5RS.
(string-ref str num) => char
String-ref
extracts the character at position
num from the string str. The position of
the first character of a string is zero. Num may not
be negative and it must be less than the length of str.
String-ref
returns the extracted character. The
following rules apply:
(string-ref "x" 0) => #\x (string-ref "xyz" 0) => #\x (string-ref "xyz" 2) => #\z (string-ref "xyz" 3) => bottom (string-ref "xyz" -1) => bottom (string-ref 'non-string 0) => bottom (string-ref "xyz" 'non-number) => bottom
The string-ref
procedure conforms to R5RS.
(substring str1 num1 num2) => str2
The substring
primitive returns a new string containing
a substring of str1. The substring to be extracted
is described by the arguments num1 and
num2 as follows: Num1 is the position of
the first character to be extracted, and num2 is
the position of the first character not to be extracted.
Positions start at zero. The following assertion must hold:
(<= num1 num2 (string-length str1))
The following rules apply:
(substring "" 0 0) => "" (substring "xyz" 0 0) => "" (substring "xyz" 0 3) => "xyz" (substring "xyz" 0 1) => "x" (substring "xyz" 1 3) => "yz" (substring 'non-string 0 0) => bottom (substring "xyz" 'non-number 0) => bottom (substring "xyz" 0 'non-number) => bottom
The substring
procedure conforms to R5RS.
(write-to-string form) => string
The write-to-string
procedure writes the external
representation of form to a string and then returns that
string.
Unambiguous external representation written by
write-to-string
may be read back using the
read-from-string
procedure. The original
form a and the car part of the re-read form b
are guaranteed to be equal in the sense of
(equal? a (car b))
.
They will not be identical, though (see eq?
).
The following rules apply:
(write-to-string 'foo) => "foo" (write-to-string #\a) => "#\\a" (write-to-string 123) => "123" (write-to-string "hello") => "\"hello\"" (write-to-string "\"hi!\"") => "\"\\\"hi!\\\"\"" (write-to-string '(x . y)) => "(x . y)" (write-to-string #\space) => "#\\space" (write-to-string #f) => "#f" (write-to-string (lambda (x) x)) => "#<procedure (x)>" (write-to-string car) => "#<primitive car>" (write-to-string cond) => "#<syntax cond>"
The write-to-string
procedure is a SketchyLISP extension.
(vector-length vector) => integer
The vector-length
procedure evaluates to length of
a vector. The length of a vector equals the number of its members.
The following rules apply:
(vector-length #()) => 0 (vector-length #(a)) => 1 (vector-length #(a b c d)) => 4 (vector-length 'non-vector) => bottom
The vector-length
procedure conforms to R5RS.
(vector-ref vec num) => datum
Vector-ref
extracts the member at position
num from the vector vec. The position of
the first member of a vector is zero. Num may not
be negative and it must be less than the length of vec.
Vector-ref
returns the extracted datum. The
following rules apply:
(vector-ref #(x) 0) => x (vector-ref #(x y z) 0) => x (vector-ref #(x y z) 2) => z (vector-ref #(x y z) 3) => bottom (vector-ref #(x y z) -1) => bottom (vector-ref 'non-string 0) => bottom (vector-ref (xyz) 'non-number) => bottom
The vector-ref
procedure conforms to R5RS.
(delete-file str) => {#t,#f}
(delete-file str)
deletes the file named in str.
It returns #t
, if the given file could be deleted and
otherwise #f
. Possible reasons why a file could not be
deleted include
The following rules apply:
(delete-file "foo") => #t ; file foo deleted (delete-file "foo") => #f ; file foo not deleted (delete-file 'non-string) => bottom
The delete-file
procedure is a SketchyLISP Extension.
(display form) => #<void>
The display
procedure writes a nicely formatted copy
of form to the output stream. Formatting includes
the removal of quotation marks of strings and the #\
prefix of chars. The #\space
and #\newline
objects print as a blank character and a newline character.
Display
does not print the external
representation of a form. Use write
to print
unambiguous representations of forms.
Output is formatted as follows:
(display 'foo) writes foo (display #\a) writes a (display 123) writes 123 (display "hello") writes hello (display "\"hi\"") writes "hi" (display '(x . y)) writes (x . y) (display #\space) writes (display #f) writes #f (display (lambda (x) x)) writes #<procedure (x)> (display car) writes #<primitive car> (display cond) writes #<syntax cond>
The display
procedure conforms to R5RS.
(eof-object? form) => {#t,#f}
(Eof-object? x)
evaluates to #t
, if
x is the EOF object and otherwise to #f
.
The EOF object is returned by the read
and
read-char
procedures when attempting to read beyond
the end of the input stream.
Because the EOF object has no unambiguous external representation, the following examples use the one defined here:
(define eof (begin (with-output-to-file "empty-file" (lambda () ())) (with-input-from-file "empty-file" read)))
Given above definition, the following rules apply:
(eof-object? eof) => #t (eof-object? 'any-other-object) => #f
The eof-object?
procedure conforms to R5RS.
(peek-char) => char
Peek-char
reads a single character from the input
stream and returns a matching char object. Like read-char
it reads raw characters. Unlike read-char
, it does not
advance to the next character in the input stream. When no characters
are available from the input stream, the EOF object is returned.
The peek-char
procedure conforms to R5RS.
(read) => datum
Read
reads the external representation of a form
from the input stream, converts it to internal representation, and
returns it. After reading a single form, read
returns. Any text following the form in the input stream will
be left there. Read
is capable of reading any unambiguous
external representation that was written by write
.
Read
skips over all sorts of comments found in its
input.
When read
is applied to an input stream that does not
hold any input, it returns the EOF object which can be checked using
the eof-object?
procedure.
The top level loop of the SketchyLISP interpreter uses read
to parse programs.
Here are some sample applications of read
:
(read)foo => foo (read) foo => foo (read) 'foo => 'foo (read) foo bar => foo ; bar is left in the input stream (read) "hello" => "hello" (read) #\x => #\x (read) #\space => #\space (read) #\; => #\; (read) #t => #t (read) (x . y) => (x . y) (read) #|...|# x => x (read) #<foo> => bottom ; unreadable object
The read
procedure conforms to R5RS.
(read-char) => char
Read-char
reads a single character from the input
stream and returns a matching char object. Unlike read
it does not parse its input, but reads raw characters. If multiple
characters are available from the input stream, read-char
returns only the first one and leaves the remaining input in the
stream. When no characters are available from the input stream,
the EOF object is returned.
Here are some sample applications of read-char
:
(read-char)x => #\x (read-char) x => #\space ; x is left in the input stream (read-char)( => #\( (read-char); => ; (read-char) => #\newline
The read-char
procedure conforms to R5RS.
(with-input-from-file str fun) => datum
The with-input-from-file
procedure opens the file named
in the string str and connects the input stream to that file.
In this context, it applies the procedure fun, which must be
a procedure of zero arguments. As soon as the procedure returns, the
file is closed and the input stream is connected to the source that
was in effect before.
All applications of read
, read-char
,
or peek-char
inside of fun will read from the
given file. Applications of with-input-from-file
evaluate
to the value of (fun)
.
In case the specified file does not exist, applications of
with-input-from-file
evaluate to bottom.
A sample application of this procedure follows. The file foo is assumed to contain the text (foo "hello" 5).
(with-input-from-file "foo" read) => (foo "hello" 5)
The with-input-from-file
procedure conforms to R5RS.
(with-output-to-file str fun) => datum
The with-output-to-file
procedure opens the file named
in the string str and connects the output stream to that file.
In this context, it applies the procedure fun, which must be
a procedure of zero arguments. As soon as the procedure returns, the
file is closed and the output stream is connected to the file or device
that was in effect before.
All applications of write
, write-char
, or
display
inside of fun will write to the given file.
Applications of with-output-to-file
evaluate to the value of
(fun)
.
In case the file specified in str already exists, its content will be overwritten.
The following sample application of this procedure writes the form (foo "hello" 5) to the file foo.
(with-output-to-file "foo" (lambda () (write '(foo "hello" 5)))) => #<void>
The with-output-to-file
procedure conforms to R5RS.
(write form) => #<void>
The write
procedure writes the external representation
of form to the output stream.
Unambiguous external representation written by write
may be read back using the read
procedure. The original
form a and the re-read form b are
guaranteed to be equal in the sense of (equal? a b)
.
They will not be identical, though (see eq?
).
Output is formatted as follows:
(write 'foo) writes foo (write #\a) writes #\a (write 123) writes 123 (write "hello") writes "hello" (write "\"hi\"") writes "\"hi\"" (write '(x . y)) writes (x . y) (write #\space) writes #\space (write #f) writes #f (write (lambda (x) x)) writes #<procedure (x)> (write car) writes #<primitive car> (write cond) writes #<syntax cond>
The write
procedure conforms to R5RS.
(write-char #\c) => #<void>
The write-char
procedure writes the given character
to the output stream.
Output is formatted as follows:
(write-char '#x) writes x (write-char '#X) writes X (write-char '#;) writes ; (write-char '#() writes (
The write-char
procedure conforms to R5RS.
[<<Syntax] | [Contents] [Index] | [Syntax Transformation>>] |