Pointer to constants are pointing to a statically memory area which identifies each individual constant. With Inlab Scheme the following constants exist:
This is the boolean constant “true”.
This is the boolean constant “false”, which is the only object that counts as false in conditional expressions like if and cond.
This is the “unassigned constant” which may be bound to a variable. If a variable bound to this constant is used an error is signalled. This constant is used to detect some errors in derived expressions.
The empty list () is actually implemented as a separate constant and distinct from #f .
Symbols are parsed (internalised) by read in lower case. Symbols have a name that has all properties of a string. It is guaranteed that a symbol with the same name is always the same in the sense of eq?.
Inlab Scheme supports inexact reals (floating points) and exact integers as numeric data types:
Exact Integers can be as large as the native word size of the machine on which Inlab Scheme is compiled on (32 bit or 64 bit signed). Internally, some static space is allocated for “often used” integers, integers lying outside the “often used” range are allocated dynamically. This actually means that eq? on integers may fail, even is two integers contain the same value. You should - as always - use eqv? to compare integer values for equality.
Inexact real numeric values are implemented using floating point standard arithmetic as provided by the host machine.
Inlab Scheme supports numeric character values from 0 to 255. Characters are static allocated objects what guarantees eq? to return #t for the same character.
As specified in the R4RS the following special character names are supported:
A “#" followed by a 3 digit decimal value with leading zeroes may be used to specify each possible value from 0 to 255.
> #\048 #\0 > #\078 #\N
Characters are self evaluating. As specified in the R4RS case is significant in #<character> but not in #<character name>.
Strings are kept in the main heap and are dynamically allocated. Strings may contain any sequence of 8 bit characters (including 0), which allows storing any binary data using strings. To enter any possible 8 bit character value a followed by a three digit decimal value in the range 0 … 255 may be used. A special character that cannot be represented another way is also printed using that notation.
> "abc\\def" "abc\\def" > "\078" "N"
Although the length of a string internally has no special limit (depends on the current heap size and the architecture of the machine) there is a limit in (read) which limits the length of a token to a maximum of 10KB. This actually means that a single string constant (e.g. in a program) larger than 10KB will cause a parsing error in Inlab Scheme.
Lists are implemented the well known and usual way using “cons cells”, there is nothing special to tell here.
> '(a . (b . (c . ()))) (a b c) >
Vectors are implemented as specified by the R4RS as a “heterogeneous structure” allocated in heap. Vectors are not self-evaluating and an error is signalled (artificially) when a vector is about to be evaluated.
> '#(this is a vector) #(this is a vector) >
The port concept of R4RS is extended by string-input-ports, string-output-ports, Unix popen-ports (reading and writing) and by providing access to UNIX stderr via current-error-port.
Three types of procedures are implemented: Primitive procedures (implemented in C), compound procedures (written in Scheme) and syntax procedures which for the low level macro facility of Inlab Scheme (also written in Scheme).
> car #<primitive-procedure car> > caar #<compound-procedure caar> > (pp caar) (lambda (x) (car (car x))) ok > quasiquote #<syntax-procedure quasiquote> > (pp quasiquote) (named-syntax-lambda (quasiquote expr env) (internal-qq (cadr expr) 1 1)) ok >
Primitive procedures have a name associated with it. Primitive procedures are printed as #<primitive-procedure <name> >.
> car #<primitive-procedure car> > (define a car) a > a #<primitive-procedure car>
Compound procedures may have a name associated with it for debugging purposes. Compound procedures with a name may be generated using named-lambda or using (define (<name> <args>) <body>).
Compound procedures with a name are printed as #<compound-procedure <name», anonymous compound procedures (as returned by lambda) as #<compound-procedure>.
> (define (plus1 n) (+ n 1)) plus1 > plus1 #<compound-procedure plus1> > (lambda (n) (+ n 1)) #<compound-procedure> >
Inlab Scheme implements its macro facility using syntax procedures, which are first class objects as compound procedures are.
A similar naming scheme to compound procedures is implemented by syntax-lambda and named-syntax-lambda.
> (pp let*) (named-syntax-lambda (let* expr env) ((named-lambda (() binding-list body-list) (if (null? binding-list) (list (cons 'lambda (cons '() body-list))) (append (list 'let (list (car binding-list))) (list (cons 'let* (cons (cdr binding-list) body-list)))))) (cadr expr) (cddr expr))) ok >