-
Notifications
You must be signed in to change notification settings - Fork 5
Features
Adapted from the Revised Report on the Algorithmic Language Scheme
Scheme is a statically scoped and properly tail recursive dialect of the Lisp programming language invented by Guy Lewis Steele Jr. and Gerald Jay Sussman. It was designed to have exceptionally clear and simple semantics and few different ways to form expressions.
Boolean constants evaluate to themselves, so they do not need to be quoted in programs.
-
#t
is true -
#f
is the only value that counts as false in a conditional expression. All other Scheme values, including#t
, count as true.
Unlike some other Lisp dialects, Scheme distinguishes #f
and the empty list '()
from each other.
Scheme numbers are treated as abstract data, as independent of their representation as possible. The available types number, complex, real, rational, and integer are arranged into a tower of sub-types in which each level is a subset of the level above it:
- number
- complex number e.g 2+i
- real number, e.g 3.01,
- rational number, e.g 1/4 or 0.25
- integer, e.g. 4, #xFF or 254
For example, 3 is an integer. Therefore 3 is also a rational, a real, and a complex number. The predicates number?, complex?, real?, rational?, and integer? can be used to determine the type of a given number. Note there is no simple relationship between a number's type and its representation inside. For example 3.0 or 3 could an integer while 3 can denote a real (that is also an integer).
Numbers can be exact or inexact. Inexact numbers are output with a decimal, with an exponential sign like 1e+10 or with the prefix #i
Numbers can be represented as binary, octal, decimal or hexadecimal.i
Integers like 1 or -4 or 3.0 (inexact) are mapped to ABAP type tv_int i
. Change this custom type to int8
in include YY_LIB_LISP
if available.
TYPES tv_int TYPE i. " integer data type, use int8 if available
Reals are mapped to the decfloaf34
type.
TYPES tv_real TYPE decfloat34.
They are some special real number +inf.0 (positive infinity), -inf.0, +nan.0 (Not a Number) and -nan.0.
Fractions with a numerator and a denominator, both integer values. Example of rational numbers:
1/3
(+ 3/5 0.4)
Fractions with
-
nil
is supported as the empty list'()
for compatibility, it is not a false value is Scheme. eof-object
-
(define <variable> <expression>)
binds one identifier to an expression. -
(define (<func> <params>) <body>)
defines a procedure (lambda) and binds one identifier to the function.
A lambda expression (lambda <formals> <body>)
evaluates to an anonymous procedure;
-
<formals>
a list of formal parameters (arguments list) -
<body>
a sequence of zero or more definitions followed by one or more expressions to be evaluated - The environment in effect when the lambda expression was evaluated is remembered as part of the procedure.
When the procedure is later called with some actual arguments, the environment in which the lambda expression was evaluated will be extended by binding the variables in the formal argument list to fresh locations, and the corresponding actual argument values will be stored in those locations. (A fresh location is one that is distinct from every previously existing location.)
Next, the expressions in the body of the lambda expression (which, if it contains definitions, represents a letrec*
form) will be evaluated sequentially in the extended environment.
The results of the last expression in the body will be returned as the results of the procedure call.
(lambda (x) (+ x x)) => ; a procedure
((lambda (x) (+ x x)) 4) => 8
(define reverse-subtract
(lambda (x y) (- y x)))
(reverse-subtract 7 10) => 3
(define add4
(let ((x 4))
(lambda (y) (+ x y))))
(add4 6) => 10
<formals>
have one of the following forms:
-
(<variable_1> ...)
: The procedure takes a fixed number of arguments; when the procedure is called, the arguments will be stored in fresh locations that are bound to the corresponding variables. -
<variable>
: The procedure takes any number of arguments; when the procedure is called, the sequence of actual arguments is converted into a newly allocated list, and the list is stored in a fresh location that is bound to<variable>
. -
(<variable_1> ... <variable_n> . <variable_n+1>)
: If a space-delimited period precedes the last variable, then the procedure takes n or more arguments, where n is the number of formal arguments before the period (it is an error if there is not at least one). The value stored in the binding of the last variable will be a newly allocated list of the actual arguments left over after all the other actual arguments have been matched up against the other formal arguments.
It is an error for a <variable_i>
to appear more than once in <formals>
.
((lambda x x) 3 4 5 6) => (3 4 5 6)
((lambda (x y . z) z)
3 4 5 6) => (5 6)
A case-lambda expression evaluates to a procedure that accepts a variable number of arguments and is lexically scoped in the same manner as a procedure resulting from a lambda expression.
When the (case-lambda <clause> ...)
procedure is called, the first <clause>
for which the arguments agree with <formals>
is selected, where agreement is specified as for the <formals>
of a lambda expression. The variables of <formals>
are bound to fresh locations, the values of the arguments are stored in those locations, the <body>
is evaluated in the extended environment, and the results of <body>
are returned as the results of the procedure call.
-
define-syntax
not implemented yet
Hygienic macros are not implemented yet, but the keyword define-syntax
is reserved. Support for non-hygienic macros is implemented with the special forms:
-
define-macro
Common-Lisp style macros -
macroexpand
-
gensym
-
call-with-current-continuation
andcall/cc
are reserved special forms not implemented yet
-
do
-
(let <bindings> <body>)
The binding constructslet
,let*
,letrec
,letrec*
give Scheme a block structure. The syntax is identical, but they differ in the regions they establish for their variable bindings. In alet
expression, the initial values are computed before any of the variables become bound; -
in a
let*
expression, the bindings and evaluations are performed sequentially; -
in
letrec
andletrec*
expressions, all bindings are in effect while their initial values are being computed, thus allowing mutually recursive definitions.
-
if
Evaluates the first argument. If true, the second argument is evaluated. If not, a third argument is evaluated, otherwise nil (false) is returned -
(cond <clause1> <clause2> . . . )
The last<clause>
can be an else clause,(else <expression1> <expression2> ... )
. -
(and <test1> ... )
The<test>
expressions are evaluated from left to right, and if any expression evaluates to#f
then#f
is returned. Any remaining expressions are not evaluated. If all the expressions evaluate to true values, the values of the last expression are returned. If there are no expressions, then#t
is returned. -
(or <test1> ... )
The<test>
expressions are evaluated from left to right, and the value of the first expression that evaluates to a true value is returned. Any remaining expressions are not evaluated. If all expressions evaluate to #f or if there are no expressions, then #f is returned. -
(case <key> <clause_1> <clause_2> ...)
can be any expression. Each clause has the form((<datum_1> ...) <expression_1> <expression_2> ...)
. Alternatively, a<clause>
can be of the form((<datum_1> ...) => <expression>)
. The last<clause>
can be an else clause, which has one of the forms(else <expression_1> <expression_2> ...)
or(else => <expression>)
.(case (* 2 3) ((2 3 5 7) 'prime) ((1 4 6 8 9) 'composite)) ; => composite (case (car '(c d)) ((a) 'a) ((b) 'b)) ; => unspecified '() (case (car '(c d)) ((a e i o u) 'vowel) ((w y) 'semivowel) (else => (lambda (x) x))) ; => c
Guarded Evaluation:
-
(unless <test> <expression_1> <expression_2> ...)
If expression<test>
evaluates to#f
, then the expressions are evaluated in order. The value of the last expression is returned, or'()
. -
(when <test> <expression_1> <expression_2> ...)
If expression<test>
evaluates to a true value, the expressions are evaluated in order. The value of the last expression is returned, or'()
.
-
begin
is a sequencing construct: evaluates all arguments as expressions from left to right, and the value of the last expressio is returnd; a nice way to string a lot of expressions together to be executed
-
lambda
,do
,named let
-
quote
Returns the argument verbatim, without evaluating it -
quasiquote
(nested quasiquoting not supported yet) -
unquote
,
-
unquote-splicing
,@
-
(set! <variable> <expression>)
assignment.<Expression>
is evaluated, and the resulting value is stored in the location to which<variable>
is bound. It is an error if<variable>
is not bound either in some region enclosing theset!
expression or else globally. The result of theset!
expression is unspecified.
-
delay
andforce
not implemented yet
-
read
-
newline
-
display
-
write
-
not
-
apply
-
(map proc list1 list2 ... )
It is an error ifproc
does not accept as many arguments as there are lists and return a single value. Themap
procedure appliesproc
element-wise to the elements of the lists and returns a list of the results, in order. If more than one list is given and not all lists have the same length, map terminates when the shortest list runs out. -
(for-each proc list1 list2 ... )
It is an error ifproc
does not accept as many arguments as there are lists. The arguments tofor-each
are like the arguments tomap
, butfor-each
callsproc
for its side effects rather than for its values. Unlikemap
,for-each
is guaranteed to callproc
on the elements of the lists in order from the first element(s) to the last, and the value returned byfor-each
is unspecified. If more than one list is given and not all lists have the same length,for-each
terminates when the shortest list runs out.
-
list
makes a list out of all given arguments -
(make-list m)
returns a list of length n and every atom is an empty list -
length
length of given list -
(list-tail list k)
returns the subchain of list obtained by omitting the first k elements -
(list-ref list k)
returns the kth element of list. -
list-copy
returns a copy of a list. -
(list->vector list)
returns a newly created vector initialized to the elements of the list list. Order is preserved. -
iota
-
null?
Tests if the input is nil or not. returns #t if the object is the null list'()
. It returns #t if the object is anything else. -
cons
takes two arguments and returns a new pair. The pair is list if the second argument is a list or the empty list. The first element is the head and the argument is the the tail.(cons '1 '2) is (1 . 2) (cons '1 '(2 3 4)) is (1 2 3 4) (cons '(1 2 3) '(4 5 6)) is ((1 2 3) 4 5 6)
-
car
returns the first member of a list or a pair, or an exception is the argument is not a list or nil given an empty(car '(123 245 564 898)) is 123 (car '(first second third)) is first (car '(this (is no) more difficult)) is this
-
cdr
returns the tail of a list, which will be a list, or nil, given an empty list (or nil) -
caar
-
cadr
-
cdar
-
cddr
-
caaar
,caadr
, ...cdddr
-
caaaar
, ...cddddr
-
set-car!
-
set-cdr!
-
append
pure/functional append - Creates a new list by append the last element to the concatenation of all previous lists -
append!
faster but unsafe, faster, not in R7RS. Apart from the last list, each list is linked to the next vaiset-cdr!
. -
reverse
reverse list -
(memq obj list)
return the first sublist of list whosecar
isobj
, where the sublists of list are the non-empty lists returned by(list-tail list k)
for k less than the length of list. If obj does not occur in list, then #f (not the empty list) is returned.memq
useseq?
to compare obj with the elements of list -
memv
useseqv?
to compare obj with the elements of list -
member
usesequal?
to compare obj with the elements of list -
( assq obj alist)
association list (alist
) must be a list of pairs: Find the first pair in alist whosecar
field isobj
, and returns that pair. If no pair inalist
hasobj
as itscar
, then#f
(not the empty list) is returned.assq
useseq?
to compareobj
with thecar
fields of the pairs inalist
, whileassv
useseqv?
andassoc
usesequal?
-
assv
-
assoc
-
(make-vector k)
returns a newly allocated vector of k elements. -
(make-vector k fill)
if a second argument is given, then each element is initialized to fill. Otherwise the initial contents of each element is unspecified. -
(vector-fill! vector fill)
or(vector-fill! vector fill start)
or(vector-fill! vector fill start end)
storesfill
in the elements ofvector
betweenstart
andend
.(define a (vector 1 2 3 4 5)) (vector-fill! a 'smash 2 4) a => #(1 2 smash smash 5)
-
(vector obj ...)
returns a newly allocated vector whose elements contain the given arguments. It is analogous to list.(vector 'a 'b 'c) => #(a b c)
-
(vector-length vector)
returns the number of elements in vector as an exact integer -
(vector-ref vector k)
returns the contents of element k of vector. It is an error if k is not a valid index of vector.(vector-ref '#(1 1 2 3 5 8 13 21) 5) => 8 (vector-ref '#(1 1 2 3 5 8 13 21) (exact (round (* 2 (acos -1))))) => 13
-
(vector-set! vector k obj)
-
(vector->list vector start end)
returns a newly allocated list of the objects contained in the elements of vector between start and end. Order is preserved.Start
(inclusive) andEnd
(exclusive) are optional
Bytevectors represent blocks of binary data. They are fixed-length sequences of bytes, where a byte is an exact integer in the range from 0 to 255 inclusive. A bytevector is typically more space-efficient than a vector containing the same values.
The length of a bytevector is the number of elements that it contains. This number is a non-negative integer that is fixed when the bytevector is created. The valid indexes of a bytevector are the exact non-negative integers less than the length of the bytevector, starting at index zero as with vectors.
Bytevectors are written using the notation #u8(byte ... ). For example, a bytevector of length 3 containing the byte 0 in element 0, the byte 10 in element 1, and the byte 5 in element 2 can be written as follows:
#u8(0 10 5)
Bytevector constants are self-evaluating, so they do not need to be quoted in programs.
bytevector?
make-bytevector
bytevector
bytevector-length
bytevector-u8-ref
bytevector-u8-set!
bytevector-copy
bytevector-copy!
bytevector-append
utf8->string
string->utf8
-
(digit-value char)
returns the numeric value (0 to 9) of its argument if it is a numeric digit (that is, ifchar-numeric?
returns#t
), or#f
on any other character.(digit-value #\3) => 3 (digit-value #\x0664) => 4 (digit-value #\x0AE6) => 0 (digit-value #\x0EA6) => #f
-
char->integer
-
integer->char
-
char-uppercase
-
char-downcase
-
char-alphabetic?
-
char-numeric?
-
char-whitespace?
-
char-upper-case?
-
char-lower-case?
-
char=?
-
char<?
-
char>?
-
char<=?
-
char>=?
-
char-ci=?
-
char-ci<?
-
char-ci>?
-
char-ci<=?
-
char-ci>=?
-
nil?
same alsnull?
(alias added for compatibility with Common Lisp) -
eq?
-
eqv?
-
equal?
Tests if the given arguments are equal (either by symbol or number) or, in the case of a list, whether it is the same list.equal?
returns the same aseqv?
when applied to booleans, symbols, numbers, (WiP characters, ports,) procedures, and the empty list. If two objects areeqv?
, they must beequal?
as well. In all other cases,equal?
may return either#t
or#f
. Even if its arguments are circular data structures,equal?
must always terminate.
-
string?
-
hash?
-
number?
-
integer?
-
list?
-
vector?
-
pair?
-
procedure?
-
symbol?
-
boolean?
-
boolean=?
accepts a list as argument -
vector?
-
alist?
>
>=
<
<=
=
-
current-input-port
-
current-output-port
-
current-error-port
-
open-input-string
-
open-output-string
-
get-output-string
-
close-input-port
-
close-output-port
-
close-error-port
-
input-port?
-
output-port?
-
textual-port?
-
binary-port?
-
input-port-open?
-
output-port-open?
-
eof-object?
-
make-hash
Create a hash -
hash-get
Get an element from a hash -
hash-insert
Insert an element into a hash -
hash-remove
Remove an element from a hash hash-keys
-
string
-
make-string
-
number->string
-
(string->number string)
(string->number "100") ; => 100 (string->number "1e2") ; => 100.0
-
(string->number string radix)
Returns a number of the maximally precise representation expressed by the given string. It is an error if radix is not 2, 8, 10, or 16.(string->number "100" 16) ; => 256
-
string->list
-
string->symbol
-
symbol->string
-
string-append
-
string-length
-
(string-copy string)
-
(string-copy string start)
-
(string-copy string start end)
returns a newly allocated copy of the part of the given string betweenstart
andend
.(define a "Yui") (define b (string-copy a)) (list a b) => ( "Yui" "Yui" )
-
(substring string start end)
returns a newly allocated string formed from the characters of string beginning with indexstart
and ending with indexend
. This is equivalent to callingstring-copy
with the same arguments, but is provided for backward compatibility and stylistic flexibility. -
string-set!
-
string=?
-
string-ci=?
-
string<?
-
string-ci<?
-
string>?
-
string-ci>?
-
string<=?
-
string-ci<=?
-
string>=?
-
string-ci>=?
-
+
add -
-
subtract -
*
multiply -
/
divide -
abs
-
sin
-
cos
-
tan
-
asin
-
acos
-
atan
-
sinh
-
cosh
-
tanh
-
asinh
-
acosh
-
atanh
-
expt
-
exp
-
log
-
sqrt
-
floor
-
ceiling
-
truncate
-
round
-
remainder
-
modulo
-
quotient
-
(random n)
returns an integer between 0 and n-1, where n must be an integer larger 0. Random is not part of the Scheme standard -
max
-
min
-
gcd
-
lcm
=
zero?
positive?
negative?
odd?
even?
-
ab-data
-
ab-function
-
ab-func-param
-
ab-table
-
ab-append-row
(WiP) -
ab-delete-row
(WiP) -
ab-get-row
(WiP) -
ab-get-value
-
ab-set-value
-
ab-get
-
ab-set
-
ab-sy
-
sql-query
ADBC execute SQL -
define-query
ADBC prepare SQL