Preface
This document provides a complete list of procedures and special forms implemented in version 2.00 of STklos. Originally, the language implemented by STklos was (nearly) compliant with the language described in the Revised5 Report on the Algorithmic Language Scheme (aka R5RS) [R5RS]. The fist public release of STklos was published in January 2001.
Since the first STklos release, Scheme evolved and is now defined in the R7RS report [R7RS]. Consequently, the current version of STklos is compliant to this iteration of the language. Furthermore, STklos also offers most of the libraries defined in R7RS-large, a set of standard libraries.
This document states the compliance of each construction relatively to these reports, or if it is a STklos extension.
Licences
-
STklos program and supporting files are published under the terms of the GNU General Public Licence version 2 or later. This licence is available at the following URL: https://www.gnu.org/licenses/gpl-3.0.html
-
The manual you’re now reading is published under the terms of the GNU Free Documentation License or later (see Appendix B).
1. Introduction
1.1. Overview of STklos
STklos is the successor of STk [STk], a Scheme interpreter which was tightly connected to the Tk graphical toolkit [Tk]. STk had an object layer which was called STklos. At this time, STk was used to denote the base Scheme interpreter and STklos was used to denote its object layer, which was an extension. For instance, when programming a GUI application, a user could access the widgets at the (low) Tk level, or access them using a neat hierarchy of classes wrapped in STklos.
Since the object layer is now more closely integrated with the language, the new system has been renamed STklos and STk is now used to designate the old system.
Compatibility with STk:
STklos has been
completely rewritten and as a consequence, due to new
implementation choices, old STk programs are not fully
compatible with the new system. However, these changes are very
minor and adapting a STk program for the STklos system is
generally quite easy. The only programs which need heavier work
are programs which use Tk without objects, since the new
preferred GUI system is now based on GTK+
[GTK]. Programmers used to GUI programming using
STklos classes will find that both system, even if not
identical in every points, share the same philosophy.
1.2. Lexical Conventions
1.2.1. Identifiers
In STklos, by default, identifiers which start (or end) with a colon
“:” are considered as keywords. For instance :foo
and
bar:
are STklos keywords, but not:key
is not a
keyword. Alternatively, to be compatible with other Scheme implementations,
the notation #:foo
is also available to denote the keyword of name
foo
. See Section 4.14 for more information.
The reader behavior, concerning keywords, can also be changed by the following directives:
-
the
#!keyword-colon-position-none
tells the reader that colon in a symbol should not be interpreted as a keyword; -
the
#!keyword-colon-position-before
tells the reader that a symbol starting with a colon should be interpreted as a keyword; -
the
#!keyword-colon-position-after
tells the reader that a symbol ending with a colon should be interpreted as a keyword; -
the
#!keyword-colon-position-both
tells the reader that a symbol starting or ending with a colon should be interpreted as a keyword
In any case, the notation #:key
is always read as a keyword.
By default, STklos is case sensitive as specified by R7RS. This behavior can be changed by
-
the
--case-insensitive
option used for the commandsstklos
orstklos-compile
-
the
#!fold-case
directive which can appear anywhere comments are permitted but must be followed by a delimiter. This directive (and the#!no-fold-case
) are treated as comments, except that they affect the reading of subsequent data from the same port. The#!fold-case
directive causes subsequent identifiers and character names to be case-folded as if bystring-foldcase
. It has no effect on character literals. The#!no-fold-case
directive causes the reader to a non-folding behavior.
1.2.2. Comments
There are four types of comments in STklos:
-
a semicolon
;
indicates the start of a comment. This kind of comment extends to the end of the line (as described in R5RS). -
multi-lines comment use the classical Lisp convention: a comment begins with
#|
and ends with|#
. This form of comment is now defined by SRFI-30 (Nested Multi-line Comments). -
a sharp sign followed by a semicolon
#;
comments the next Scheme expression. This is useful to comment a piece of code which spans multiple lines -
comments can also be introduced by
#!
. Such a comment extends to the end of the line which introduces it. This extension is particularly useful for building STklos scripts. On most Unix implementations, if the first line of a script looks like this:
#!/usr/bin/env stklos
then the script can be started directly as if it was a binary program. STklos is loaded behind the scene and executes the script as a Scheme program. This form is compatible with the notation introduced in SRFI-22 (Running Scheme Scripts on Unix).
Note that, as a special case, that the sequences #!key
,
#!optional
and #!rest
are respectively converted
to the STklos keywords #:key
, #:optional
and
#:rest
. This permits to Scheme lambdas, which accepts
keywords and optional arguments, to be compatible with DSSSL lambdas
[DSSSL].
1.2.3. Here Strings
Here strings permit to easily enter multilines strings in programs.
The sequence of characters #<<
starts a here string. The characters
following this sequence #<<
until a newline character define a terminator for
the here string. The content of the string includes all characters between
the #<<
line and a line whose only content is the specified terminator.
No escape sequences are recognized between the starting and terminating lines.
Example: the sequence
#<<EOF
abc
def
ghi
EOF
is equivalent to the string
"abcndefn ghi"
1.2.4. Other Notations
STk accepts all the notations defined in R5RS plus
-
#true
and#false
are other names for the constants#t
and#f
as proposed by R7RS. -
[]
Brackets are equivalent to parentheses. They are used for grouping and to build lists. A list opened with a left square bracket must be closed with a right square bracket (see Section 4.4). -
:
a colon at the beginning or the end of a symbol introduces a keyword. Keywords are described in section Keywords (see _Section 4.14). -
#n=
is used to represent circular structures. The value given ofn
must be a number. It is used as a label, which can be referenced later by a#n#
notation (see below). The scope of the label is the expression being read by the outermostread
. -
#n#
is used to reference some object previously labeled by a#n=
notation; that is,#n#
represents a pointer to the object labeled exactly by#n=
. For instance, the object returned by the following expression
(let* ((a (list 1 2))
(b (cons 'x a)))
(list a b))
can also be represented in this way:
(#0=(1 2) (x . #0#))
2. Expressions
This chapter describes the main forms available in STklos. R5RS constructions are given very succinctly here for reference. See [R5RS] for a complete description.
2.1. Literal expressions
R5RS syntax
The quoting mechanism is identical to R5RS, except that keywords constants evaluate "to themselves" as numerical constants, string constants, character constants, and boolean constants
'"abc" => "abc"
"abc" => "abc"
'145932 => 145932
145932 => 145932
'#t => #t
#t => #t
:foo => :foo
':foo => :foo
R5RS requires to quote constant lists and constant vectors. This is not necessary with STklos. |
2.2. Procedures
STklos syntax
A lambda expression evaluates to a procedure. STklos lambda expression
have been extended to allow a optional and keyword parameters.
<formals>
should have one of the following forms:
(<variable1> …)
-
The procedure takes a fixed number of arguments; when the procedure is called, the arguments will be stored in the bindings of the corresponding variables. This form is identical to R5RS.
<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 the binding of the
<variable>
. This form is identical to R5RS. (<variable1> … <variablen> . <variablen+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 (there must be 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. This form is identical to R5RS.
(<variable1 … <variablen> [:optional …] [:rest …] [:key …])
-
This form is specific to STklos and allows to have procedure with optional and keyword parameters. The form
:optional
allows to specify optional parameters. All the parameters specified after:optional
to the end of<formals>
(or until a:rest
or:key
) are optional parameters. An optional parameter can declared as:-
variable
: if a value is passed when the procedure is called, it will be stored in the binding of the corresponding variable, otherwise the value#f
will be stored in it. -
(variable value)
: if a value is passed when the procedure is called, it will be stored in the binding of the corresponding variable, otherwisevalue
will be stored in it. -
(variable value test?)
: if a value is passed when the procedure is called, it will be stored in the binding of the corresponding variable, otherwisevalue
will be stored in it. Furthermore,test?
will be given the value#t
if a value is passed for the given variable, otherwisetest?
is set to#f
.
-
Hereafter are some examples using :optional
parameters
((lambda (a b :optional c d) (list a b c d)) 1 2)
=> (1 2 #f #f)
((lambda (a b :optional c d) (list a b c d)) 1 2 3)
=> (1 2 3 #f)
((lambda (a b :optional c (d 100)) (list a b c d)) 1 2 3)
=> (1 2 3 100)
((lambda (a b :optional c (d #f d?)) (list a b c d d?)) 1 2 3)
=> (1 2 3 #f #f)
The form :rest
parameter is similar to the dot notation seen before.
It is used before an identifier to collects the parameters in a single
binding:
((lambda (a :rest b) (list a b)) 1)
=> (1 ())
((lambda (a :rest b) (list a b)) 1 2)
=> (1 (2))
((lambda (a :rest b) (list a b)) 1 2 3)
=> (1 (2 3))
The form :key
allows to use keyword parameter passing. All the parameters
specified after :key
to the end of <formals>
are keyword parameters. A
keyword parameter can be declared using the three forms given for optional
parameters. Here are some examples illustrating how to declare and how to use
keyword parameters:
((lambda (a :key b c) (list a b c)) 1 :c 2 :b 3)
=> (1 3 2)
((lambda (a :key b c) (list a b c)) 1 :c 2)
=> (1 #f 2)
((lambda (a :key (b 100 b?) c) (list a b c b?)) 1 :c 2)
=> (1 100 2 #f)
At last, here is an example showing :optional
:rest
and :key
parameters
(define f (lambda (a :optional b :rest c :key d e)
(list a b c d e)))
(f 1) => (1 #f () #f #f)
(f 1 2) => (1 2 () #f #f)
(f 1 2 :d 3 :e 4) => (1 2 (:d 3 :e 4) 3 4)
(f 1 :d 3 :e 4) => (1 #f (:d 3 :e 4) 3 4)
STklos procedure
Returns #t
if obj
is a procedure created with the lambda
syntax and
#f
otherwise.
STklos syntax
Each <clause>
should have the form (<formals> <body>)
, where
<formals>
is a formal arguments list as for lambda
.
Each <body>
is a <tail-body>
, as defined in R5RS.
A case-lambda
expression evaluates to a procedure that
accepts a variable number of arguments and is lexically scoped in
the same manner as procedures resulting from lambda
expressions. When the procedure is called with some arguments
v1 … vk
, then 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 v1 … vk
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.
It is an error for the arguments not to agree with the <formals>
of any <clause>
.
This form is defined in SRFI-16 (Syntax for procedures of variable arity).
(define plus
(case-lambda
(() 0)
((x) x)
((x y) (+ x y))
((x y z) (+ (+ x y) z))
(args (apply + args))))
(plus) => 0
(plus 1) => 1
(plus 1 2 3) => 6
((case-lambda
((a) a)
((a b) (* a b)))
1 2 3) => error
2.3. Assignments
R5RS syntax
The first form of set!
is the R5RS one:
<Expression>
is evaluated, and the resulting value is stored in
the location to which <variable>
is bound. <Variable>
must be bound
either in some region enclosing the set!
expression or at top level.
(define x 2)
(+ x 1) => 3
(set! x 4) => unspecified
(+ x 1) => 5
The second form of set!
is defined in SRFI-17 (Generalized set!):
This special form set!
is extended so the first operand can be a procedure application, and not
just a variable. The procedure is typically one that extracts a component
from some data structure. Informally, when the procedure is called in the
first operand of set!
, it causes the corresponding component to be
replaced by the second operand. For example,
(set! (vector-ref x i) v)
would be equivalent to:
(vector-set! x i v)
Each procedure that may be used as the first operand to set!
must have
a corresponding setter procedure. The procedure setter
(see below)
takes a procedure and returns the corresponding setter procedure.
So,
(set! (proc arg ...) value)
is equivalent to the call
((setter proc) arg ... value)
The result of the set!
expression is unspecified.
STklos procedure
Returns the setter associated to a proc
. Setters are defined in the
SRFI-17 (Generalized set!) document. A setter proc, can be used in a generalized
assignment, as described in set!
.
To associate s
to the procedure p
, use the following form:
(set! (setter p) s)
For instance, we can write
(set! (setter car) set-car!)
The following standard procedures have pre-defined setters:
(set! (car x) v) == (set-car! x v)
(set! (cdr x) v) == (set-cdr! x v)
(set! (string-ref x i) v) == (string-set! x i v)
(set! (vector-ref x i) v) == (vector-set! x i v)!
(set! (slot-ref x 'name) v) == (slot-set! x 'name v)
(set! (struct-ref x 'name) v) == (struct-set! x 'name v)
Furhermore, Parameter Objects (see Section 4.21) are their own setter:
(real-precision) => 15
(set! (real-precision) 12)
(real-precision) => 12
2.4. Conditionals
R5RS syntax
An if
expression is evaluated as follows: first, <test>
is
evaluated. If it yields a true value, then <consequent>
is
evaluated and its value(s) is(are) returned. Otherwise <alternate>
is evaluated and its value(s) is(are) returned. If <test>
yields a
false value and no <alternate>
is specified, then the result of the
expression is void.
(if (> 3 2) 'yes 'no) => yes
(if (> 2 3) 'yes 'no) => no
(if (> 3 2)
(- 3 2)
(+ 3 2)) => 1
R5RS syntax
In a cond
, each <clause>
should be of the form
(<test> <expression1> ...)
where <test>
is any expression. Alternatively, a <clause>
may be
of the form
(<test> => <expression>)
The last <clause>
may be an "else clause," which has the form
(else <expression1> <expression2> ...)
A cond expression is evaluated by evaluating the <test>
expressions
of successive <clause>
s in order until one of them evaluates to a
true value When a <test>
evaluates to a true value, then the
remaining <expression>
s in its <clause>
are evaluated in order,
and the result(s) of the last <expression>
in the <clause>
is(are)
returned as the result(s) of the entire cond expression. If the
selected <clause>
contains only the <test>
and no <expression>`s,
then the value of the `<test>
is returned as the result. If the
selected <clause>
uses the ⇒
alternate form, then the
<expression>
is evaluated. Its value must be a procedure that
accepts one argument; this procedure is then called on the value of
the <test>
and the value(s) returned by this procedure is(are)
returned by the cond expression.
If all <test>
s evaluate to false
values, and there is no else clause, then the result of the
conditional expression is void; if there is an else clause,
then its <expression>
s are evaluated, and the value(s) of the last
one is(are) returned.
(cond ((> 3 2) 'greater)
((< 3 2) 'less)) => greater
(cond ((> 3 3) 'greater)
((< 3 3) 'less)
(else 'equal)) => equal
(cond ((assv 'b '((a 1) (b 2))) => cadr)
(else #f)) => 2
R7RS syntax
In a case
, each <clause>
should have the form
((<datum1> ...) <expression1> <expression2> ...),
where each <datum>
is an external representation of some object. All the
<datum>`s must be distinct. The last `<clause>
may be an "else clause," which
has the form
(else <expression1> <expression2> ...).
A case expression is evaluated as follows. <Key>
is evaluated and
its result is compared against each <datum>
. If the result of
evaluating <key>
is equivalent (in the sense of eqv?) to a
<datum>
, then the expressions in the corresponding <clause>
are
evaluated from left to right and the result(s) of the last expression
in the <clause>
is(are) returned as the result(s) of the case
expression. If the result of evaluating <key>
is different from
every <datum>
, then if there is an else clause its expressions are
evaluated and the result(s) of the last is(are) the result(s) of the
case expression; otherwise the result of the case expression is void.
If the selected <clause>
or else clause uses the ⇒
alternate
form, then the expression
is evaluated. It is an error if
its value is not a procedure accepting one argument. This
procedure is then called on the value of the hkeyi and the
values returned by this procedure are returned by the case
expression.
(case (* 2 3)
((2 3 5 7) 'prime)
((1 4 6 8 9) 'composite)) => composite
(case (car '(c d))
((a) 'a)
((b) 'b)) => void
(case (car '(c d))
((a e i o u) 'vowel)
((w y) 'semivowel)
(else 'consonant)) => consonant
(case (car '(c d))
((a e i o u) 'vowel)
((w y) 'semivowel)
(else => (lambda (x) (x)))) => c
R5RS syntax
The <testi>
expressions are evaluated from left to right, and the
value of the first expression that evaluates to a false value is
returned. Any remaining expressions are not evaluated. If all the
expressions evaluate to true values, the value of the last expression
is returned. If there are no expressions then #t
is returned.
(and (= 2 2) (> 2 1)) => #t
(and (= 2 2) (< 2 1)) => #f
(and 1 2 'c '(f g)) => (f g)
(and) => #t
R5RS syntax
The <testi>
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 false values, the value of the last expression
is returned. If there are no expressions then #f
is returned.
(or (= 2 2) (> 2 1)) => #t
(or (= 2 2) (< 2 1)) => #t
(or #f #f #f) => #f
(or (memq 'b '(a b c))
(/ 3 0)) => (b c)
STklos syntax
If the <test>
expression yields a true value, the <expression>
s are
evaluated from left to right and the value of the last <expression>
is
returned. Otherwise, when
returns void.
STklos syntax
If the <test>
expression yields a false value, the <expression>
s are
evaluated from left to right and the value of the last <expression>
is
returned. Otherwise, unless
returns void.
2.5. Binding Constructs
The three binding constructs let
, let*
, and
letrec
are available in STklos.
These constructs differ in the regions they establish for
their variable bindings. In a let
expression, the initial values are
computed before any of the variables become bound; in a let*
expression, the bindings and evaluations are performed sequentially; while in a
letrec
expression, all the bindings are in effect while their initial
values are being computed, thus allowing mutually recursive definitions.
STklos also provides a fluid-let
form which is described below.
R5RS syntax
In a let
, <bindings>
should have the form
((<variable1> <init1>) ...)
where each <initi>
is an expression, and <body>
should be a sequence of one or
more expressions. It is an error for a <variable>
to appear more than once in
the list of variables being bound.
The <init>
s are evaluated in the current environment (in some
unspecified order), the <variable>
s are bound to fresh locations holding the
results, the <body>
is evaluated in the extended environment, and the value(s)
of the last expression of <body>
is(are) returned. Each binding of a
<variable>
has <body>
as its region.
(let ((x 2) (y 3))
(* x y)) => 6
(let ((x 2) (y 3))
(let ((x 7)
(z (+ x y)))
(* z x))) => 35
The second form of let
, which is generally called a named let,
is a variant on the syntax of let which provides a more general
looping construct than do
and may also be used to
express recursions. It has the same syntax and semantics as ordinary
let except that <variable>
is bound within <body>
to a procedure whose
formal arguments are the bound variables and whose body is <body>
.
Thus the execution of <body>
may be repeated by invoking the procedure
named by <variable>
.
(let loop ((numbers '(3 -2 1 6 -5))
(nonneg '())
(neg '()))
(cond ((null? numbers) (list nonneg neg))
((>= (car numbers) 0)
(loop (cdr numbers)
(cons (car numbers) nonneg)
neg))
((< (car numbers) 0)
(loop (cdr numbers)
nonneg
(cons (car numbers) neg)))))
=> ((6 1 3) (-5 -2))
R5RS syntax
In a let*
, <bindings>
should have the same form as in a let
(however, a
<variable> can appear more than once in the list of variables being bound).
Let*
is similar to let
, but the bindings are performed sequentially
from left to right, and the region of a binding indicated by
(<variable> <init>)
is that part of the let*
expression to the right of the binding. Thus
the second binding is done in an environment in which the first binding is
visible, and so on.
(let ((x 2) (y 3))
(let* ((x 7)
(z (+ x y)))
(* z x))) => 70
R5RS syntax
<bindings> should have the form as in let
.
The <variable>
s are bound to fresh locations holding undefined
values, the <init>
s are evaluated in the resulting environment (in
some unspecified order), each <variable>
is assigned to the result
of the corresponding <init>
, the <body>
is evaluated in the
resulting environment, and the value(s) of the last expression in
<body>
is(are) returned. Each binding of a <variable>
has the
entire letrec
expression as its region, making it possible to define
mutually recursive procedures.
(letrec ((even? (lambda (n)
(if (zero? n)
#t
(odd? (- n 1)))))
(odd? (lambda (n)
(if (zero? n)
#f
(even? (- n 1))))))
(even? 88))
=> #t
R7RS syntax
<bindings> should have the form as in let
and body is a sequence
of zero or more definitions followed by one or more expressions.
The <variable>
s are bound to fresh locations, each variable
is
assigned in left-to-right order to the result of evaluating the
corresponding init
, the body
is evaluated in the resulting
environment, and the values of the last expression in body
are
returned. Despite the left-to-right evaluation and assignment order,
each binding of a variable
has the entire letrec*
expression as its
region, making it possible to define mutually recursive procedures.
If it is not possible to evaluate each init
without assigning or
referring to the value of the corresponding variable
or the
variable
of any of the bindings that follow it in bindings
, it is
an error.
(letrec* ((p (lambda (x)
(+ 1 (q (- x 1)))))
(q(lambda (y)
(if (zero? y)
0
(+ 1 (p (- y 1))))))
(x (p 5))
(y x))
y) => 5
R7RS syntax
Each <formals>
should be a formal arguments list as for a lambda
expression.
The <expression>
s are evaluated in the current environment,
the variables of the <formals>
are bound to fresh locations, the return
values of the <expression>
s are stored in the variables, the <body>
is
evaluated in the extended environment, and the values of the last expression
of <body>
are returned.
The matching of each <formals>
to values is as for the matching of
<formals>
to arguments in a lambda
expression, and it is an error
for an <expression>
to return a number of values that does not match
its corresponding <formals>
.
(let-values (((root rem) (exact-integer-sqrt 32)))
(* root rem)) => 35
(let ((a 'a) (b 'b) (x 'x) (y 'y))
(let-values (((a b) (values x y))
((x y) (values a b)))
(list a b x y))) => (x y a b)
R7RS syntax
Each <formals>
should be a formal arguments list as for a lambda
expression.
let*-values
is similar to let-values
, but the bindings are performed
sequentially from left to right, and the region of a binding indicated by
(<formals> <expression>)
is that part of the let*-values
expression to
the right of the binding. Thus the second binding is done in an environment
in which the first binding is visible, and so on.
(let ((a 'a) (b 'b) (x 'x) (y 'y))
(let*-values (((a b) (values x y))
((x y) (values a b)))
(list a b x y))) => (x y x y)
R7RS procedure
The form define-values
creates multiple definitions from a single expression
returning multiple values. Here, expression
is evaluated, and the formals
are bound to the return values in the same way that the formals
in a
lambda expression are matched to the arguments in a procedure call.
(let ()
(define-values (x y) (exact-integer-sqrt 17))
(list x y)) => (4 1)
(let ()
(define-values (x y) (values 1 2))
(+ x y)) => 3
(let ()
(define-values (x . y) (values 1 2 3))
(list x y) => (1 (2 3))
STklos syntax
The <bindings>
are evaluated in the current environment, in some
unspecified order, the current values of the variables present in
<bindings>
are saved, and the new evaluated values are assigned to the
<bindings>
variables. Once this is done, the expressions of <body>
are evaluated sequentially in the current environment; the value of the
last expression is the result of fluid-let
. Upon exit, the stored
variables values are restored. An error is signalled if any of the
<bindings>
variable is unbound.
(let* ((a 'out)
(f (lambda () a)))
(list (f)
(fluid-let ((a 'in)) (f))
(f))) => (out in out)
When the body of a fluid-let
is exited by invoking a continuation,
the new variable values are saved, and the variables are set to their old
values. Then, if the body is reentered by invoking a continuation, the old
values are saved and new values are restored. The following example illustrates
this behavior
(let ((cont #f)
(l '())
(a 'out))
(set! l (cons a l))
(fluid-let ((a 'in))
(set! cont (call-with-current-continuation (lambda (k) k)))
(set! l (cons a l)))
(set! l (cons a l))
(if cont (cont #f) l)) => (out in out in out)
2.6. Sequencing
R5RS syntax
The <expression>
s are evaluated sequentially from left to right, and the
value(s) of the last <expression>
is(are) returned. This expression type is
used to sequence side effects such as input and output.
(define x 0)
(begin (set! x 5)
(+ x 1)) => 6
(begin (display "4 plus 1 equals ")
(display (+ 4 1))) |- 4 plus 1 equals 5
=> void
STklos syntax
The <expression>
s are evaluated sequentially from left to right,
and the value(s) of the last <expression> is(are) returned as in a
begin
form. Within a tagbody
form expressions which are keywords
are considered as tags and the special form (→ tag)
is used to
transfer execution to the given tag. This is a very low level
form which is inspired on tabgody
Common Lisp’s form. It can be useful
for defining new syntaxes, and should probably not be used as is.
(tagbody ;; an infinite loop
#:1 (display ".")
(-> #:1))
(let ((v 0))
(tagbody
#:top (when (< v 5)
(display v)
(set! v (fx+ v 1))
(-> #:top)))) |- 01234
(tagbody (display 1)
(tagbody (display 2)
(-> #:inner)
(display "not printed")
#:inner
(display 3)
(-> #:outer)
(display "not printed too"))
#:outer
(display "4")) |- 1234
2.7. Iterations
R5RS syntax
Do
is an iteration construct. It specifies a set of variables to be
bound, how they are to be initialized at the start, and how they are
to be updated on each iteration. When a termination condition is met,
the loop exits after evaluating the <expr>
s.
Do
expressions are evaluated as follows: The <init>
expressions
are evaluated (in some unspecified order), the <var>
s are bound
to fresh locations, the results of the <init>
expressions are stored
in the bindings of the <var>
s, and then the iteration phase
begins.
Each iteration begins by evaluating <test>
; if the result is false
then the <command>
expressions are evaluated in order for effect,
the <step>
expressions are evaluated in some unspecified order, the
<var>
s are bound to fresh locations, the results of the <step>
s
are stored in the bindings of the <var>
s, and the next iteration
begins.
If <test>
evaluates to a true value, then the <expr>
s are
evaluated from left to right and the value(s) of the last <expr>
is(are) returned. If no <expr>
s are present, then the value of
the do expression is void.
The region of the binding of a <var>
consists of the entire do
expression except for the <init>
s. It is an error for a <var>
to
appear more than once in the list of do variables.
A <step>
may be omitted, in which case the effect is the same as if
(<var> <init> <var>)
had been written.
(do ((vec (make-vector 5))
(i 0 (+ i 1)))
((= i 5) vec)
(vector-set! vec i i)) => #(0 1 2 3 4)
(let ((x '(1 3 5 7 9)))
(do ((x x (cdr x))
(sum 0 (+ sum (car x))))
((null? x) sum))) => 25
STklos syntax
Evaluates the count
expression, which must return an
integer and then evaluates the <expression>
s once for each
integer from zero (inclusive) to count
(exclusive), in order,
with the symbol var
bound to the integer; if the value of
count
is zero or negative, then the <expression>
s are not
evaluated. When the loop completes, result
is evaluated and its
value is returned as the value of the dotimes
construction. If
result
is omitted, dotimes
result is void.
(let ((l '()))
(dotimes (i 4 l)
(set! l (cons i l)))) => (3 2 1 0)
STklos syntax
Evaluates the count
expression, which must return an
integer and then evaluates the <expression>
s once for each
integer from zero (inclusive) to count
(exclusive). The result of
repeat
is undefined.
This form could be easily simulated with dotimes
. Its interest is
that it is faster.
(repeat 3 (display ".")) => prints "..."
(repeat 0 (display ".")) => prints nothing
STklos syntax
While
evaluates the <expression>
s until <test>
returns a false
value. The value returned by this form is void.
STklos syntax
Until
evaluates the <expression>
s until <while>
returns a false
value. The value returned by this form is void.
2.8. Delayed Evaluation
R5RS syntax
The delay
construct is used together with the procedure force
to implement lazy evaluation or call by need. (delay
<expression>)
returns an object called a promise) which at some
point in the future may be asked (by the force
procedure) to
evaluate <expression>
, and deliver the resulting value.
The effect of <expression>
returning multiple values is unpredictable.
See the description of force
for a more complete
description of delay
.
R7RS syntax
The expression (delay-force expression)
is conceptually similar
to (delay (force expression))
, with the difference that forcing the result
of delay-force
will in effect result in a tail call to (force expression)
,
while forcing the result of (delay (force expression))
might not. Thus
iterative lazy algorithms that might result in a long series of chains of
delay
and force
can be rewritten using delay-force
to prevent consuming
unbounded space during evaluation.
The special form delay-force
appears with name lazy
in SRFI-45 (Primitives for Expressing Iterative Lazy Algorithms).
R5RS procedure
Forces the value of promise
(see primitive delay).
If no value has been computed for the promise, then a value is
computed and returned. The value of the promise is cached
(or "memoized") so that if it is forced a second time, the
previously computed value is returned.
(force (delay (+ 1 2))) => 3
(let ((p (delay (+ 1 2))))
(list (force p) (force p))) => (3 3)
(define a-stream
(letrec ((next (lambda (n)
(cons n (delay (next (+ n 1)))))))
(next 0)))
(define head car)
(define tail (lambda (stream) (force (cdr stream))))
(head (tail (tail a-stream))) => 2
Force
and delay
are mainly intended for programs written in
functional style. The following examples should not be considered
to illustrate good programming style, but they illustrate the
property that only one value is computed for a promise, no matter
how many times it is forced.
(define count 0)
(define p (delay (begin (set! count (+ count 1))
(if (> count x)
count
(force p)))))
(define x 5)
p => a promise
(force p) => 6
p => a promise, still
(begin (set! x 10)
(force p)) => 6
See R5RS for details on a posssible way to implement
force and delay .
|
R7RS procedure
Returns #t
if obj
is a promise, otherwise returns #f
.
R7RS procedure
The make-promise
procedure returns a promise which,
when forced, will return obj
. It is similar to delay
, but
does not delay its argument: it is a procedure rather than
syntax. If obj
is already a promise, it is returned.
The primitve make-promise
appears with name eager
in
SRFI-45.
2.9. Quasiquotation
R5RS syntax
"Backquote" or "quasiquote" expressions are useful for constructing a
list or vector structure when most but not all of the desired structure
is known in advance. If no commas appear within the <template>
,
the result of evaluating `<template>
is equivalent to the result of
evaluating '<template>
. If a comma appears within the
<template>
, however, the expression following the comma is evaluated
("unquoted") and its result is inserted into the structure instead of
the comma and the expression. If a comma appears followed immediately
by an at-sign (@), then the following expression must evaluate to a
list; the opening and closing parentheses of the list are then
"stripped away" and the elements of the list are inserted in place of the comma
at-sign expression sequence. A comma at-sign should only appear within
a list or vector <template>
.
`(list ,(+ 1 2) 4) => (list 3 4)
(let ((name 'a)) `(list ,name ',name))
=> (list a (quote a))
`(a ,(+ 1 2) ,@(map abs '(4 -5 6)) b)
=> (a 3 4 5 6 b)
`((foo ,(- 10 3)) ,@(cdr '(c)) . ,(car '(cons)))
=> ((foo 7) . cons)
`#(10 5 ,(sqrt 4) ,@(map sqrt '(16 9)) 8)
=> #(10 5 2 4 3 8)
Quasiquote forms may be nested. Substitutions are made only for unquoted components appearing at the same nesting level as the outermost backquote. The nesting level increases by one inside each successive quasiquotation, and decreases by one inside each unquotation.
`(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f)
=> (a `(b ,(+ 1 2) ,(foo 4 d) e) f)
(let ((name1 'x)
(name2 'y))
`(a `(b ,,name1 ,',name2 d) e))
=> (a `(b ,x ,'y d) e)
The two notations `<template>
and (quasiquote <template>)
are identical
in all respects. ,<expression>
is identical to (unquote <expression>)
, and
,@<expression>
is identical to (unquote-splicing <expression>)
.
2.10. Macros
STklos supports hygienic macros such as the ones defined in R5RS as well as low level macros.
Low level macros are defined with define-macro
whereas R5RS macros are
defined with define-syntax
.[1]. Hygienic macros use the implementation
called Macro by Example (Eugene Kohlbecker, R4RS) done by Dorai
Sitaram. This implementation generates low level STklos macros. This
implementation of hygienic macros is not expensive.
The major drawback of this implementation is that the macros are not
referentially transparent (see section Macros in R4RS for
details). Lexically scoped macros (i.e., let-syntax
and
letrec-syntax
are not supported). In any case, the problem of
referential transparency gains poignancy only when let-syntax
and
letrec-syntax
are used. So you will not be courting large-scale
disaster unless you’re using system-function names as local variables
with unintuitive bindings that the macro can’t use. However, if you
must have the full R5RS macro functionality, you can do
(require "full-syntax")
to have access to the more featureful (but also more expensive)
versions of syntax-rules. Requiring "full-syntax"
loads the
version 2.1 of an implementation of hygienic macros by Robert Hieb
and R. Kent Dybvig.
STklos syntax
define-macro
can be used to define low-level macro
(i.e. ,(emph "non hygienic") macros). This form is similar to the
defmacro
form of Common Lisp.
(define-macro (incr x) `(set! ,x (+ ,x 1)))
(let ((a 1)) (incr a) a) => 2
(define-macro (when test . body)
`(if ,test ,@(if (null? (cdr body)) body `((begin ,@body)))))
(macro-expand '(when a b)) => (if a b)
(macro-expand '(when a b c d))
=> (if a (begin b c d))
(define-macro (my-and . exprs)
(cond
((null? exprs) #t)
((= (length exprs) 1) (car exprs))
(else `(if ,(car exprs)
(my-and ,@(cdr exprs))
#f))))
(macro-expand '(my-and a b c))
=> (if a (my-and b c) #f)
R5RS syntax
<Define-syntax>
extends the top-level syntactic environment by binding
the <identifier>
to the specified transformer.
<transformer-spec> should be an instance of syntax-rules .
|
(define-syntax let*
(syntax-rules ()
((let* () body1 body2 ...)
(let () body1 body2 ...))
((let* ((name1 val1) (name2 val2) ...)
body1 body2 ...)
(let ((name1 val1))
(let* (( name2 val2) ...)
body1 body2 ...))))
R5RS syntax
<literals>
is a list of identifiers, and each <syntax-rule>
should be of
the form
(pattern template)
An instance of <syntax-rules>
produces a new macro transformer by
specifying a sequence of hygienic rewrite rules. A use of a macro
whose name is associated with a transformer specified by
<syntax-rules> is matched against the patterns contained in the
<syntax-rules>, beginning with the leftmost syntax-rule. When a match is
found, the macro use is transcribed hygienically according to the
template.
Each pattern begins with the name for the macro. This name is not involved in the matching and is not considered a pattern variable or literal identifier.
For a complete description of the Scheme pattern language, refer to R5RS. |
R5RS syntax
<Bindings>
should have the form
((<keyword> <transformer spec>) ...)
Each <keyword>
is an identifier, each <transformer spec>
is an instance of
syntax-rules
, and <body>
should be a sequence of one or more expressions. It
is an error for a <keyword>
to appear more than once in the list of keywords
being bound.
The <body>
is expanded in the syntactic environment obtained by
extending the syntactic environment of the let-syntax
expression with macros
whose keywords are the <keyword>
s, bound to the specified transformers. Each
binding of a <keyword>
has <body>
as its region.
let-syntax is available only after having required the file
"full-syntax" .
|
(let-syntax ((when (syntax-rules ()
((when test stmt1 stmt2 ...)
(if test
(begin stmt1
stmt2 ...))))))
(let ((if #t))
(when if (set! if 'now))
if)) => now
(let ((x 'outer))
(let-syntax ((m (syntax-rules () ((m) x))))
(let ((x 'inner))
(m)))) => outer
R5RS syntax
Syntax of letrec-syntax
is the same as for let-syntax
.
The <body>
is expanded in the syntactic environment obtained by
extending the syntactic environment of the letrec-syntax
expression
with macros whose keywords are the <keyword>
s, bound to the specified
transformers. Each binding of a <keyword>
has the <bindings>
as well
as the <body>
within its region, so the transformers can transcribe
expressions into uses of the macros introduced by the letrec-syntax
expression.
letrec-syntax is available only after having required the file
"full-syntax" .
|
(letrec-syntax
((my-or (syntax-rules ()
((my-or) #f)
((my-or e) e)
((my-or e1 e2 ...)
(let ((temp e1))
(if temp
temp
(my-or e2 ...)))))))
(let ((x #f)
(y 7)
(temp 8)
(let odd?)
(if even?))
(my-or x
(let temp)
(if y)
y))) => 7
STklos procedure
macro-expand
returns the macro expansion of form
if it is a macro call,
otherwise form
is returned unchanged.
(define-macro (add1 x) `(+ ,x 1))
(macro-expand '(add1 foo)) => (+ foo 1)
(macro-expand '(car bar)) => (car bar)
macro-expand
returns the full macro expansion of form
, that is it repeats
the macro-expansion, while the expanded form contains macro calls.
(define-macro (add2 x) `(add1 (add1 ,x)))
(macro-expand '(add2 foo)) => (add1 (add1 foo))
(macro-expand* '(add2 foo)) => (+ (+ foo 1) 1)
macro-expand and macro-expand* expand only the global macros.
|
3. Program structure
Since its origin, STklos offers a module system which can be used to organize a program into separate environments (or name spaces). The module system is directly inherited from STk. This module system is largely inspired from the one of Tung and Dybvig exposed in Tung and Dybvig paper [TuD96]. As this module system, STk and STklos modules are defined to be easily used in an interactive environment.
STklos modules provide a clean way to organize and enforce the barriers between the components of a program. At this time, the current version of Scheme was R5RS which didn’t define a module system. However, since then, R7RS has defined the notion of libraries, which are similar, in the intent, to STklos modules. Consequently, STklos offers both systems: modules and libraries (the latter being implemented on top of the former).
3.1. Modules
STklos syntax
Define-module
evaluates the expressions <expr1>
, <expr2>
… which
constitute the body of the module <name>
in the environment of that module.
Name
must be a valid symbol or a list constitued of symbols or positive integers.
If name
has not already been used to define a module, a new module, named name
,
is created. Otherwise, the expressions <expr1>
, <expr2>
… are evaluated in
the environment of the (old) module <name>
[2]
Definitions done in a module are local to the module and do not interact with the definitions in other modules. Consider the following definitions,
(define-module M1
(define a 1))
(define-module M2
(define a 2)
(define b (* 2 x)))
(define-module (M2 m)
(define a 100)
(define x 200))
Here, three modules are defined and they all bind the symbol a
to a
value. However, since a
has been defined in distinct modules
they denote three different locations.
The STklos
module, which is predefined, is a special module which
contains all the global bindings of a R7RS program. A symbol
defined in the STklos
module, if not hidden by a local definition, is
always visible from inside a module. So, in the previous exemple, the
x
symbol refers the x
symbol defined in the STklos
module, which is
of course different of the one defined in the module (M2 m)
.
The result of define-module
is void.
Internally, modules name are always represented by a symbol. If the module
name is given as a list, the internal name is built by appending all the components
of the list, separated by a '/' symbol. So the third module can be referenced with the
name (M2 m) of M2/m .
|
STklos procedure
STklos modules are first class objects and find-module
returns the
module object associated to name
, if it exists. If there is no module
associated to name
, an error is signaled if no default
is
provided, otherwise find-module
returns default
.
STklos procedure
Returns #t
if object
is a module and #f
otherwise.
(module? (find-module 'STklos)) => #t
(module? 'STklos) => #f
(module? 123 'no) => no
STklos procedure
Returns the internal name (a symbol) associated to a module
. As said before,
module name is always represented as a symbol, even if expressed as a list.
(define-module (M a) ) ; or M/a
(define-module (M b) ) ; or M/b
(define-module M/c ) ; or (M c)
(map (lambda(x) (module-name (find-module x))) '( (M a) M/b (M c) ))
=> (M/a M/b M/c)
STklos procedure
Returns the current module.
(define-module M
(display
(cons (eq? (current-module) (find-module 'M))
(eq? (current-module) (find-module 'STklos))))) |- (#t . #f)
STklos syntax
Changes the value of the current module to the module with the given name
.
The expressions evaluated after select-module
will take place in
module name
environment. Module name
must have been created
previously by a define-module
. The result of select-module
is
void.
Select-module
is particularly useful when debugging since it
allows to place toplevel evaluation in a particular module. The
following transcript shows an usage of select-module
.
[3]):
stklos> (define foo 1)
stklos> (define-module bar (define foo 2))
stklos> foo
1
stklos> (select-module bar)
bar> foo
2
bar> (select-module stklos)
stklos>
STklos procedure
Returns the value bound to symbol
in module
. If symbol
is not bound,
an error is signaled if no default
is provided, otherwise symbol-value
returns default
. Module
can be an object module or a module name.
STklos procedure
Returns the value bound to symbol
in module
. If symbol
is not bound,
an error is signaled if no default
is provided, otherwise symbol-value
returns default
.
Note that this function searches the value of symbol
in module
and in the STklos module if module is not a R7RS library.
STklos procedure
Returns #t is symb
is bound in module
and #f otherwise. If module
is
omitted it defaults to the current module.
STklos procedure
Returns the list of symbols defined or imported in module
. Module
can be an object module or a module name.
STklos procedure
Returns the the list of symbols acessible in module
(that is the symbols
defined in module
and the one defined in the STklos
module if module
is not a R7RS library.
STklos syntax
Specifies the symbols which are exported (i.e. visible outside
the current module). By default, symbols defined in a module are not
visible outside this module, excepted if they appear in an export
clause.
An <export spec>
takes one of the following forms:
-
<identifier>
-
(rename <identifier1> <identifier2>)
In the first form, <identifier>
names a single binding defined within or
imported into the module, where the external name for the export is the same
as the name of the binding within the module.
In the second form, the binding defined within or imported into the module and
named by <identifier1>
in each (<identifier1> <identifier2>)
pairing,
using <identifier2>
as the external name.
The result of export
is void.
the export form in STklos modules is compatible with the export
clause in R7RS libraries.
|
STklos syntax
An import declaration provides a way to import identifiers
exported by a module. Each <import set>
names a set of bindings
from a module and possibly specifies local names for the
imported bindings. It takes one of the following forms:
-
<module name>
-
(only <import set> <identifier> …)
-
(except <import set> <identifier> …)
-
(prefix <import set> <identifier>)
-
(rename <import set> (<identifier1> <identifier2>) …)
In the first form, all of the identifiers in the named
module’s export clauses are imported with the same names
(or the exported names if exported with rename
).
The additional import set
forms modify this set as follows:
-
only
produces a subset of the given <import set>} including only the listed identifiers (after any renaming). It is an error if any of the listed identifiers are not found in the original set. -
except
produces a subset of the given<import set>
, excluding the listed identifiers (after any renaming). It is an error if any of the listed identifiers are not found in the original set. -
rename
modifies the given<import set>
, replacing each instance of<identifier1>
with<identifier2>
. It is an error if any of the listed<identifiers>
are not found in the original set. -
prefix
automatically renames all identifiers in the given<import set>
, prefixing each with the specified<identifier>
.
(define-module M1
(export a b)
(define a 'M1-a)
(define b 'M1-b))
(define-module M2
(export b c d)
(define b 'M2-b)
(define c 'M2-c)
(define d 'M2-d))
(define-module M3
(import M1 M2)
(display (list a b c d))) |- (M1-a M2-b M2-c M2-d)
(define-module M4
(import M2 M1)
(display (list a b c d))) |- (M1-a M1-b M2-c M2-d)
(define-module M1
(export a b c d)
(define a 1)
(define b 2)
(define c 3)
(define d 4))
(define-module M2
(import (prefix (rename (except M1 a)
(b bb) (c cc))
M1-))
(display (module-symbols (current-module))))
|- (M1-bb M1-cc M1-d)
Here, M1
module exports the symbols a
, b
, c
and d
. In the
M2
module, the except
rule permits to import only b
, c
and
d
. With rename
, identifiers b
and c
of M1
are renamed bb
and cc
. Finally, with prefix
alls identifier names are prefixed
by M1-
.
the import form in STklos modules is compatible with the
import clause in R7RS libraries.
|
The module STklos , which contains the global variables
is always implicitly imported from a module. Furthermore,
this module is always placed at the end of the list of imported
modules.
|
Note that importing a module will try to load a file if the module is not already defined. For instance,
(define-module M
(import (srfi 1) (foo bar baz))
...)
will load the file srfi/1
and foo/bar/baz
modules (or libraries) if
they are not yet defined (habitual rules on the load paths and the load
suffixes applies to find those files).
STklos procedure
Returns the list of modules that module
imports (that is, the ones
it depends on).
STklos procedure
Returns the list of symbols exported by module
. Note that this function
returns the list of symbols given in the module export
clause and that
some of these symbols can be not yet defined.
(define-module M
(export a b (rename c M-c))
(display (module-exports (current-module))))
|- (a b M-c)
STklos procedure
Makes the module mod
immutable, so that it will be impossible
to define new symbols in it or change the value of already defined ones.
STklos procedure
Returns #t
if mod
is an immutable module and #f
otherwise. Note that the
SCHEME
module, which contains the original bindings of the STklos at boot
time, is immutable. The parameter mod
can be a module object or a module name.
(module-mutable? (find-module 'STklos)) => #t
(module-mutable? (find-module 'SCHEME)) => #f
(module-mutable? 'SCHEME) => #f
STklos syntax
This form returns the value of symbol with name s
in the module with name
mod
. If this symbol is not bound, an error is signaled if no default
is
provided, otherwise in-module
returns default
. Note that the value of s
is searched in mod
and all the modules it imports.
This form is in fact a shortcut. In effect,
(in-module my-module foo)
is equivalent to
(symbol-value* 'foo (find-module 'my-module))
STklos procedure
Returns the list of all the living modules (or libraries). Use
module-list
to obtain a list of modules without libraries.
STklos procedure
Returns the list of all the living modules.
3.2. Libraries
The library concept is defined in R7RS ans is supported in STklos. As said before, libraries are implemented with modules. Briefly stated, the library |(lib a b)| will be implemented with a module whose name is |lib/a/b| and the |STklos| module has been deleted from the import list.
R7RS syntax
The form define-library
is defined in R7RS. The <library name>
can be
a symbol or a list (as modules).
A <library declaration>
is any of
-
(export <export spec> …)
-
(import <import set> …)
-
(begin <command or definition> …)
-
(include <filename1> <filename2> …)
-
(include-ci <filename1> <filename2> …)
-
(include-library-declarations <filename1> <filename2> …)
-
(cond-expand <clause1> <clause2> …)
See R7RS for more information (or the specific entries in this document)
about each <library declaration>
.
R7RS permits to use library declarations only in
a library definition; STklos permits to use them (except
include-library-declarations ) anywhere at toplevel.
|
STklos procedure
Returns #t
if object
is a module defined as a R7RS library and #f
otherwise.
Note that R7RS libraries, since they are implemented using STklos modules, are
also modules.
(define-module a)
(define-library (b))
(module? (find-module 'a)) => #t
(module? (find-module '(b))) => #t
(library? (find-module 'a)) => #f
(library? (find-module '(b))) => #t
STklos procedure
Returns the name of lib
if it was defined as an R7RS library,
and #f
if the library is anonymous. If lib
is not a library,
library-name
raises an error. If a name is returned, it is
as a list.
(define-library (example cool-library))
(library-name (find-module 'example/cool-library)) => (example cool-library)
(library-name (find-module '(example cool-library))) => (example cool-library)
(module-name (find-module 'example/cool-library)) => example/cool-library
(module-name (find-module '(example cool-library))) => example/cool-library
(define-module example/a-module)
(library-name (find-module 'example/a-module)) => error
(library-name quotient) => error
STklos procedure
Returns the list of all the living libraries.
3.3. Variables and Constants
R5RS syntax
Theses forms bind an identifier to a a value.
The first form binds the <variable>
to the result of the evaluation of
<expression>
.
The second form of define
is equivalent to
(define <variable>
(lambda (<formals>) body))
The third define
form, where <formal>
is a single variable, is equivalent to
(define <variable>
(lambda <formals> body))
The define form accepts also the definition of higher order lambda as
defined in SRFI-219 (Define higher-order lambda).
|
STklos procedure
This form is similar to define
, except the binding of <variable>
which
is non mutable.
(define-constant a 'hello)
(set! a 'goodbye) => error
(define a 2) ; is ok (it's a new binding)
(define-constant ((foo a) b) ; foo is (lambda (a) (lambda (b) ...)))
...)
STklos procedure
Makes the symbol symb
in module mod
immutable. If mod
is not specified,
the current module is used.
(define a 1)
(symbol-mutable? 'a) => #t
(symbol-immutable! 'a)
(symbol-mutable? 'a) => #f
(set! a 10) => error
STklos procedure
Returns #t
if symb
is mutable in module
and #f
otherwise. If module
is omitted it defaults to the current module. Note that imported symbols are
always not mutable.
(define-module M
(export x)
(define x 1))
(symbol-mutable? 'x (find-module 'M)) => #t
(symbol-mutable? 'x) => error, if not defined in current module
(import M)
(symbol-mutable? 'x) => #f
4. Standard Procedures
4.1. Equivalence predicates
A predicate is a procedure that always returns a boolean value
(#t
or #f
). An equivalence predicate is the
computational analogue of a mathematical equivalence relation (it
is symmetric, reflexive, and transitive). Of the equivalence
predicates described in this section, eq?
is the finest
or most discriminating, and equal?
is the coarsest.
Eqv?
is slightly less discriminating than eq?
.
R5RS procedure
The eqv?
procedure defines a useful equivalence relation on objects.
Briefly, it returns #t
if obj1
and obj2
should normally be regarded
as the same object. This relation is left slightly open to interpretation,
but the following partial specification of eqv?
holds for all
implementations of Scheme.
The eqv?
procedure returns #t
if:
-
obj1
andobj2
are both#t
or both#f
. -
obj1
andobj2
are both symbols and(string=? (symbol->string obj1) (symbol->string obj2)) => #t
This assumes that neither obj1
norobj2
is an "uninterned symbol". -
obj1
andobj2
are both keywords and(string=? (keyword->string obj1) (keyword->string obj2)) => #t
-
obj1
andobj2
are both numbers, are numerically equal, and are either both exact or both inexact. -
obj1
andobj2
are both characters and are the same character according to thechar=?
procedure`. -
both
obj1
andobj2
are the empty list. -
obj1
andobj2
are pairs, vectors, or strings that denote the same locations in the store. -
obj1
andobj2
are procedures whose location tags are equal.
STklos extends R5RS eqv?
to take into account
the keyword type. Here are some examples:
(eqv? 'a 'a) => #t
(eqv? 'a 'b) => #f
(eqv? 2 2) => #t
(eqv? :foo :foo) => #t
(eqv? #:foo :foo) => #t
(eqv? :foo :bar) => #f
(eqv? '() '()) => #t
(eqv? 100000000 100000000) => #t
(eqv? (cons 1 2) (cons 1 2)) => #f
(eqv? (lambda () 1)
(lambda () 2)) => #f
(eqv? #f 'nil) => #f
(let ((p (lambda (x) x)))
(eqv? p p)) => #t
The following examples illustrate cases in which the above rules do
not fully specify the behavior of eqv?
. All that can be said about
such cases is that the value returned by eqv? must be a boolean.
(eqv? "" "") => unspecified
(eqv? '#() '#()) => unspecified
(eqv? (lambda (x) x)
(lambda (x) x)) => unspecified
(eqv? (lambda (x) x)
(lambda (y) y)) => unspecified
In fact, the value returned by STklos depends on
the way code is entered and can yield #t in some cases and #f
in others.
|
See R5RS for more details on eqv?
.
R5RS procedure
Eq?
is similar to eqv?
except that in some cases it is capable of
discerning distinctions finer than those detectable by eqv?
.
Eq?
and eqv?
are guaranteed to have the same behavior on symbols,
keywords, booleans, the empty list, pairs, procedures, and non-empty strings
and vectors. Eq?
's behavior on numbers and characters is
implementation-dependent, but it will always return either true or false,
and will return true only when eqv?
would also return true.
Eq?
may also behave differently from eqv?
on empty vectors
and empty strings.
Note that:
-
STklos extends R5RS
eq?
to take into account the keyword type. -
In STklos, comparison of character returns
#t
for identical characters and#f
otherwise.
(eq? 'a 'a) => #t
(eq? '(a) '(a)) => unspecified
(eq? (list 'a) (list 'a)) => #f
(eq? "a" "a") => unspecified
(eq? "" "") => unspecified
(eq? :foo :foo) => #t
(eq? :foo :bar) => #f
(eq? '() '()) => #t
(eq? 2 2) => unspecified
(eq? #A #A) => #t (unspecified in r5rs)
(eq? car car) => #t
(let ((n (+ 2 3)))
(eq? n n)) => #t (unspecified in r5rs)
(let ((x '(a)))
(eq? x x)) => #t
(let ((x '#()))
(eq? x x)) => #t
(let ((p (lambda (x) x)))
(eq? p p)) => #t
(eq? :foo :foo) => #t
(eq? :bar bar:) => #t
(eq? :bar :foo) => #f
R5RS procedure
Equal?
recursively compares the contents of pairs, vectors, and
strings, applying eqv?
on other objects such as numbers and symbols.
A rule of thumb is that objects are generally equal?
if they print the
same. Equal?
always terminates even if its arguments are circular
data structures.
(equal? 'a 'a) => #t
(equal? '(a) '(a)) => #t
(equal? '(a (b) c)
'(a (b) c)) => #t
(equal? "abc" "abc") => #t
(equal? 2 2) => #t
(equal? (make-vector 5 'a)
(make-vector 5 'a)) => #t
(equal? '#1=(a b . #1#)
'#2=(a b a b . #2#)) => #t
A rule of thumb is that objects are generally
equal? if they print the same.
|
4.2. Numbers
R5RS description of numbers is quite long and will not be given here. STklos support the full number tower as described in R5RS; see this document for a complete description.
STklos extends the number syntax of R5RS with the following
inexact numerical constants: +inf.0
(infinity), -inf.0
(negative
infinity), +nan.0
(not a number), and -nan.0
(not a number).
R5RS procedure
These numerical type predicates can be applied to any kind of
argument, including non-numbers. They return #t
if the object is of
the named type, and otherwise they return #f
. In general, if a type
predicate is true for a number then all higher type predicates are
also true for that number. Consequently, if a type predicate is
false of a number, then all lower type predicates are also false of
that number.
If z
is an inexact complex number, then (real? z)
is true if and
only if (zero? (imag-part z))
is true. If x
is an inexact real
number, then (integer? x)
is true if and only if
(and (finite? x) (= x (round x)))
(complex? 3+4i) => #t
(complex? 3) => #t
(real? 3) => #t
(real? -2.5+0.0i) => #t
(real? #e1e10) => #t
(rational? 6/10) => #t
(rational? 6/3) => #t
(integer? 3+0i) => #t
(integer? 3.0) => #t
(integer? 3.2) => #f
(integer? 8/4) => #t
(integer? "no") => #f
(complex? +inf.0) => #t
(real? -inf.0) => #t
(rational? +inf.0) => #f
(integer? -inf.0) => #f
R5RS procedure
These numerical predicates provide tests for the exactness of a quantity. For any Scheme number, precisely one of these predicates is true.
R7RS procedure
These R7RS procedures correspond to the R5RS exact→inexact
and inexact→exact
procedure respectively
R7RS procedure
Returns #t
if z is both exact and an integer; otherwise returns #f
.
(exact-integer? 32) => #t
(exact-integer? 32.0) => #f
(exact-integer? 32/5) => #f
STklos procedure
This predicates returns #t
if x
is an integer number too large to be
represented with a native integer.
(bignum? (expt 2 300)) => `#t` ;; (very likely)
(bignum? 12) => `#f`
(bignum? "no") => `#f`
R5RS procedure
These procedures return #t
if their arguments are (respectively):
equal, monotonically increasing, monotonically decreasing,
monotonically nondecreasing, or monotonically nonincreasing, and
#f
otherwise. If any of the arguments are +nan.0, all the predicates
return #f
.
(= +inf.0 +inf.0) => #t
(= -inf.0 +inf.0) => #f
(= -inf.0 -inf.0) => #t
For any finite real number x:
(< -inf.0 x +inf.0) => #t
(> +inf.0 x -inf.0) => #t
R5RS procedure
These numerical predicates test a number for a particular property,
returning #t
or #f
.
(positive? +inf.0) ==> #t
(negative? -inf.0) ==> #t
(finite? -inf.0) ==> #f
(infinite? +inf.0) ==> #t
R7RS procedure
The nan?
procedure returns #t on +nan.0
, and on complex
numbers if their real or imaginary parts or both are +nan.0
.
Otherwise it returns #f.
(nan? +nan.0) => #t
(nan? 32) => #f
(nan? +nan.0+5.0i) => #t
(nan? 1+2i) => #f
STklos procedure
Returns a NaN whose sign bit is equal to negative?
(#t
for negative,
#f
for positive), whose quiet bit is equal to quiet? (#t
for quiet,
#f
for signaling), and whose payload is the positive exact integer payload.
It is an error if payload is larger than a NaN can hold.
The optional parameter float
, is never used in STklos.
This function is defined in SRFI-208.
STklos procedure
returns #t
if the sign bit of nan
is set and #f
otherwise.
STklos procedure
returns #t
if nan
is a quiet NaN.
STklos procedure
returns the payload bits of nan
as a positive exact integer.
STklos procedure
Returns #t
if nan1
and nan2
have the same sign, quiet bit,
and payload; and #f
otherwise.
R5RS procedure
These procedures return the maximum or minimum of their arguments.
(max 3 4) => 4 ; exact
(max 3.9 4) => 4.0 ; inexact
For any real number x:
(max +inf.0 x) => +inf.0
(min -inf.0 x) => -inf.0
If any argument is inexact, then the result will also be inexact |
R7RS procedure
These procedures implement number-theoretic (integer) division. It is
an error if n2
is zero. The procedures ending in '/' return two integers;
the other procedures return an integer. All the procedures compute a
quotient q
and remainder r
such that n1=n2*q+r
.
See R7RS for more information.
(floor/ 5 2) => 2 1
(floor/ -5 2) => -3 1
(floor/ 5 -2) => -3 -1
(floor/ -5 -2) => 2 -1
(truncate/ 5 2) => 2 1
(truncate/ -5 2) => -2 -1
(truncate/ 5 -2) => -2 1
(truncate/ -5 -2) => 2 -1
(truncate/ -5.0 -2) => 2.0 -1.0%
R5RS procedure
These procedures return the sum or product of their arguments.
(+ 3 4) => 7
(+ 3) => 3
(+) => 0
(+ +inf.0 +inf.0) => +inf.0
(+ +inf.0 -inf.0) => +nan.0
(* 4) => 4
(*) => 1
(* 5 +inf.0) => +inf.0
(* -5 +inf.0) => -inf.0
(* +inf.0 +inf.0) => +inf.0
(* +inf.0 -inf.0) => -inf.0
(* 0 +inf.0) => +nan.0
For any finite number z: |
(+ +inf.0 z) => +inf.0
(+ -inf.0 z) => -inf.0
R5RS procedure
With two or more arguments, these procedures return the difference or quotient of their arguments, associating to the left. With one argument, however, they return the additive or multiplicative inverse of their argument.
(- 3 4) => -1
(- 3 4 5) => -6
(- 3) => -3
(- +inf.0 +inf.0) => +nan.0
(/ 3 4 5) => 3/20
(/ 3) => 1/3
(/ 0.0) => +inf.0
(/ -0.0) => -inf.0
(- 0.0) => -0.0
(/ 0) => error (division by 0)
R5RS procedure
Abs
returns the absolute value of its argument.
(abs -7) => 7
(abs -inf.0) => +inf.0
(abs -3+4i) => 5
(abs -3.0-4i) => 5.0
STklos extends the R7RS abs function, by allowing its
argument to be a complex number. In this case, abs returns the
magnitude of its argument.
|
R5RS procedure
These procedures implement number-theoretic (integer) division. n2 should be non-zero. All three procedures return integers.
If n1/n2
is an integer:
(quotient n1 n2) => n1/n2
(remainder n1 n2) => 0
(modulo n1 n2) => 0
If n1/n2 is not an integer:
(quotient n1 n2) => nq
(remainder n1 n2) => nr
(modulo n1 n2) => nm
where nq
is n1/n2
rounded towards zero, 0 < abs(nr) < abs(n2),
0 < abs(nm) < abs(n2), nr
and nm
differ from n1 by a multiple of n2,
nr
has the same sign as n1, and nm
has the same sign as n2.
From this we can conclude that for integers n1
and n2
with n2
not
equal to 0,
(= n1 (+ (* n2 (quotient n1 n2))
(remainder n1 n2))) => #t
provided all numbers involved in that computation are exact.
(modulo 13 4) => 1
(remainder 13 4) => 1
(modulo -13 4) => 3
(remainder -13 4) => -1
(modulo 13 -4) => -3
(remainder 13 -4) => 1
(modulo -13 -4) => -1
(remainder -13 -4) => -1
(remainder -13 -4.0) => -1.0 ; inexact
R5RS procedure
These procedures return the greatest common divisor or least common multiple of their arguments. The result is always non-negative.
(gcd 32 -36) => 4
(gcd) => 0
(lcm 32 -36) => 288
(lcm 32.0 -36) => 288.0 ; inexact
(lcm) => 1
R5RS procedure
These procedures return the numerator or denominator of their argument; the result is computed as if the argument was represented as a fraction in lowest terms. The denominator is always positive. The denominator of 0 is defined to be 1.
(numerator (/ 6 4)) => 3
(denominator (/ 6 4)) => 2
(denominator
(exact->inexact (/ 6 4))) => 2.0
R5RS procedure
These procedures return integers. Floor
returns the largest integer not
larger than x
. Ceiling
returns the smallest integer not smaller than x
.
Truncate
returns the integer closest to x
whose absolute value is not
larger than the absolute value of x
. Round
returns the closest integer
to x
, rounding to even when x
is halfway between two integers.
Round rounds to even for consistency with the default
rounding mode specified by the IEEE floating point standard.
|
If the argument to one of these procedures is inexact, then the
result will also be inexact. If an exact value is needed, the result should
be passed to the inexact→exact procedure.
|
(floor -4.3) => -5.0
(ceiling -4.3) => -4.0
(truncate -4.3) => -4.0
(round -4.3) => -4.0
(floor 3.5) => 3.0
(ceiling 3.5) => 4.0
(truncate 3.5) => 3.0
(round 3.5) => 4.0 ; inexact
(round 7/2) => 4 ; exact
(round 7) => 7
R5RS procedure
Rationalize returns the simplest rational number differing from x
by no more than y
. A rational number r1
is simpler than another
rational number r2
if r1
= p1/q1
and r2
= p2/q2
(in lowest
terms) and abs(p1) ⇐ abs(p2) and abs(q1) ⇐ abs(q2). Thus 3/5
is
simpler than 4/7
. Although not all rationals are comparable in
this ordering (consider 2/7
and 3/5
) any interval contains a
rational number that
is simpler than every other rational number in that interval (the
simpler 2/5
lies between 2/7
and 3/5
). Note that 0
= 0/1
is the
simplest rational of all.
(rationalize
(inexact->exact .3) 1/10) => 1/3 ; exact
(rationalize .3 1/10) => #i1/3 ; inexact
R5RS procedure
These procedures compute the usual transcendental functions. Log
computes the
natural logarithm of z (not the base ten logarithm). Asin
, acos
,
and atan
compute arcsine, arccosine, and arctangent, respectively.
The two-argument variant of log
computes the logarithm of x in base b as
(/ (log x) (log b))
The two-argument variant of atan
computes
(angle (make-rectangular x y))
When it is possible these procedures produce a real result from a real argument.
STklos procedure
These procedures compute the hyperbolic trigonometric functions.
(sinh 1) => 1.1752011936438
(sinh 0+1i) => 0.0+0.841470984807897i
(cosh 1) => 1.54308063481524
(cosh 0+1i) => 0.54030230586814
(tanh 1) => 0.761594155955765
(tanh 0+1i) => 0.0+1.5574077246549i
(asinh 1) => 0.881373587019543
(asinh 0+1i) => 0+1.5707963267949i
(acosh 0) => 0+1.5707963267949i
(acosh 0+1i) => 1.23340311751122+1.5707963267949i
(atanh 1) => error
(atanh 0+1i) => 0.0+0.785398163397448i
In general, (asinh (sinh x))
and similar compositions should be
equal to x
, except for inexactness due to the internal floating
point number approximation for real numbers.
(sinh (asinh 0+1i)) => 0.0+1.0i
(cosh (acosh 0+1i)) => 8.65956056235493e-17+1.0i
(tanh (atanh 0+1i)) => 0.0+1.0i
These functions will always return an exact result for the following arguments:
(sinh 0.0) => 0
(cosh 0.0) => 1
(tanh 0.0) => 0
(asinh 0.0) => 0
(acosh 1.0) => 0
(atanh 0.0) => 0
STklos procedure
These procedures convert angles from radians into degrees and from degrees into radians.
R5RS procedure
Returns the principal square root of z
. The result will have either
positive real part, or zero real part and non-negative imaginary part.
R7RS procedure
Returns the square of z
. This is equivalent to (* z z)
.
(square 42) => 1764
(square 2.0) => 4.0
R7RS procedure
Returns two non negatives integers s
and r
where
k=s2+r
and k<(s+1)2
.
(exact-integer-sqrt 4) => 2 0
(exact-integer-sqrt 5) => 2 1
R5RS procedure
Returns z1
raised to the power z2
.
0,(sup "z") is 1 if z = 0 and 0 otherwise.
|
R5RS procedure
If x1, x2, x3, and x4 are real numbers and z is a complex number such that
z = x1 + x2.i = x3 . e,(sup "i.x4")
Then
(make-rectangular x1 x2) => z
(make-polar x3 x4) => z
(real-part z) => x1
(imag-part z) => x2
(magnitude z) => abs(x3)
(angle z) => xa
where
-,(symbol "pi") < xa ⇐ ,(symbol "pi")
with xa = x4 + 2,(symbol "pi")n
for some integer n.
(angle +inf.0) => 0.0
(angle -inf.0) => 3.14159265358979
Magnitude is the same as abs for a real argument.
|
R5RS procedure
Exact→inexact
returns an inexact representation of z.
The value returned is the inexact number that is numerically closest to
the argument.
Inexact→exact
returns an exact representation of z.
The value returned is the exact number that is numerically closest to
the argument.
R5RS procedure
Radix
must be an exact integer, either 2, 8, 10, or 16. If omitted, radix
defaults to 10. The procedure number→string
takes a number and a radix
and returns as a string an external representation of the given number in
the given radix such that
(let ((number number)
(radix radix))
(eqv? number
(string->number (number->string number radix) radix)))
is true. It is an error if no possible result makes this expression true.
If z
is inexact, the radix is 10, and the above expression can be
satisfied by a result that contains a decimal point, then the result
contains a decimal point and is expressed using the minimum number of digits
(exclusive of exponent and trailing zeroes) needed to make the above expression
true; otherwise the format of the result is unspecified.
The result returned by number→string
never contains an explicit radix
prefix.
The error case can occur only when z is not a complex number or
is a complex number with a non-rational real or imaginary part.
|
If z is an inexact number represented using flonums, and
the radix is 10, then the above expression is normally satisfied by a result
containing a decimal point. The unspecified case allows for infinities,
NaNs, and non-flonum representations.
|
R5RS procedure
Returns a number of the maximally precise representation expressed by the
given string
. Radix
must be an exact integer, either 2, 8, 10, or 16.
If supplied, radix
is a default radix that may be overridden by an explicit
radix prefix in string
(e.g. ,(code ""#o177"")). If radix
is not
supplied, then
the default radix is 10. If string
is not a syntactically valid notation
for a number, then string→number
returns #f
.
(string->number "100") => 100
(string->number "100" 16) => 256
(string->number "1e2") => 100.0
(string->number "15##") => 1500.0
(string->number "+inf.0") => +inf.0
(string->number "-inf.0") => -inf.0
STklos procedure
These procedures allow the manipulation of integers as bit fields.
The integers can be of arbitrary length. Bit-and
, bit-or
and
bit-xor
respectively compute the bitwise ,(emph "and"), inclusive and
exclusive ,(emph "or"). bit-not
returns the bitwise ,(emph "not") of n
.
bit-shift
returns the bitwise ,(emph "shift") of n
. The integer n
is shifted left by m
bits; If m
is negative, n
is shifted right by
-m
bits.
(bit-or 5 3) => 7
(bit-xor 5 3) => 6
(bit-and 5 3) => 1
(bit-not 5) => -6
(bit-or 1 2 4 8) => 15
(bit-shift 5 3) => 40
(bit-shift 5 -1) => 2
STklos procedure
Return an integer in the range [0, …, n
[. Subsequent results of
this procedure appear to be independent uniformly distributed over
the range [0, …, n
[. The argument n
must be a positive integer,
otherwise an error is signaled. This function is equivalent to the eponym
function of SRFI-27 (Source of random bits).
STklos procedure
Return a real number r
such that 0 < r < 1
.
Subsequent results of this procedure appear to be independent uniformly
distributed. This function is equivalent to the eponym
function of SRFI-27 (Source of random bits).
STklos procedure
decode-float
returns three exact integers: significand
, exponent
and sign
(where -1 ⇐ sign ⇐ 1
). The values returned by
decode-float
satisfy:
n = (* sign significand (expt 2 exponent))
Here is an example of decode-float
usage.
(receive l (decode-float -1.234) l)
=> (5557441940175192 -52 -1)
(exact->inexact (* -1
5557441940175192
(expt 2 -52)))
=> -1.234
STklos procedure
encode-float
does the inverse work of decode-float
: it accepts three
numbers, significand
, exponent
and sign
, and returns the floating
point number represented by them.
When significand
is #f
, a NaN will be returned.
When significand
is #t
, positive or negative infinity is returned,
depending on the value of sign
.
Otherwise, the number returned is
n = (* sign significand (expt 2 exponent))
Both significand
and exponent
must be within their proper ranges:
0 < significand
⇐ float-max-significand
, and
float-min-exponent
⇐ exponent
⇐ float-max-exponent
.
(encode-float (#t 0 1)) => +inf.0
(encode-float (#t 0 -1)) => -inf.0
(encode-float (#f 0 1)) => +nan.0
(decode-float -0.01)
=> 5764607523034235
=> -59
=> -1
(inexact (encode-float 5764607523034235 -59 -1)) => -0.01
STklos procedure
These procedures return the maximum significand value and the
minimum and maximum values for the exponent when calling
the encode-float
procedure.
STklos procedure
Integer-length
returns the necessary number of bits to represent n
in 2’s complement, assuming a leading 1 bit when n
is negative. When
n
is zero, the procedure returns zero.
This procedure works for any type of integer (fixnums and bignums).
(integer-length -3) => 2
(integer-length -2) => 1
(integer-length -1) => 0
(integer-length 0) => 0
(integer-length 1) => 1
(integer-length 2) => 2
(integer-length 3) => 2
(integer-length (expt 2 5000)) => 5001
4.2.1. Fixnums
STklos defines small integers as fixnums. Operations on fixnums are generally faster than operations which accept general numbers. Fixnums operations, as described below, may produce results which are incorrect if some temporary computation falls outside the range of fixnum. These functions should be used only when speed really matters.
The functions defined in this section are conform to the ones defined in SRFI-143 (Fixnums)
STklos procedure
Returns #t
if obj is an exact integer within the fixnum range,
#f
otherwise.
STklos procedure
Returns the number of bits used to represent a fixnum number.
STklos procedure
These procedures return the minimum value and the maximum value of the fixnum range.
STklos procedure
fxzero?
returns #t
if obj
is the fixnum zero and returns
#f
if it is a non-zero fixnum.
(fxzero? #f) => error
(fxzero? (expt 100 100)) => error
(fxzero? 0) => #t
(fxzero? 1) => #f
STklos procedure
fxpositive?
returns #t
if obj
is a positive fixnum and returns
#f
if it is a non-positive fixnum. fxnegative?
can be used to test
if a fixnum is negative.
(fxpositive? #f) => error
(fxpositive? (expt 100 100)) => error
(fxpositive? 0) => #f
(fxpositive? 1) => #t
(fxpositive? -1) => #f
(fxnegative? 0) => #f
(fxnegative? 1) => #f
(fxnegative? -1) => #t
STklos procedure
fxodd?
returns #t
if obj
is a odd fixnum and returns
#f
if it is an even fixnum.
(fxodd? #f) => error
(fxodd? (expt 100 100)) => error
(fxodd? 0) => #f
(fxodd? 1) => #t
(fxodd? 4) => #f
(fxeven? 0) => #t
(fxeven? 1) => #f
(fxeven? 4) => #t
STklos procedure
These procedures compute (respectively) the sum, the difference, the product,
the quotient and the remainder and modulo of the fixnums fx1
and fx2
.
The call of fx-
with one parameter fx
computes the opposite of fx
, and
is equivalent in a call of fxneg
with this parameter. fxabs
computes the absolute value of fx
.
STklos procedure
These procedures compute (respectively) the square and the square root
of the fixnum fx1
.
fxsqrt
id semantically equivalent to exact-integer-sqrt (not sqrt), so
that (fxsqrt n)
returns two values a
, b
, such that a*a+b
=n
.
(fxsqrt #f) => error
(fxsqrt (expt 100 100)) => error
(fxsqrt -1) => error
(fxsqrt 0) => 0, 0
(fxsqrt 1) => 1, 0
(fxsqrt 6) => 2, 2
STklos procedure
These procedures return the maximum or minimum of their fixnum arguments.
(fxmax 3 4) => 4
(fxmax 3.9 4) => error
(fxmax) => error
(fxmax 2 -1 3) => 3
STklos procedure
These are SRFI-143 procedures that compare the fixnums fx1
, fx2
, and so on.
fx<?
and fx>?
return #t
if the arguments are in strictly
increasing/decreasing order;
fx⇐?
and fx>=?
do the same, but admit equal neighbors;
fx=?
returns #t
if the arguments are all equal.
STklos procedure
These procedures are specified in SRFI-143, and they return (respectively) the bitwise not, and, inclusive or and exclusive or of their arguments, which must be fixnums.
(fxnot 1) => -2
(fxnot 0) => -1
(fxand #x1010 #x1011) => 4112 ; = #x1010
(fxior #x1010 #x1011) => 4113 ; = #x1011
(fxxor #x1010 #x1011) => 1 ; = #x0001
STklos procedure
These procedures are specified in SRFI-143, and they perform bitwise right-shift, left-shft and shift with arbitrary direction on fixnums. The strictly left and right shifts are more efficient.
(fxarithmetic-shift-right #b100110 3) => 4 ; = #b100
(fxarithmetic-shift-left #b100110 3) => 304 ; = #b100110000
(fxarithmetic-shift #b101 2) => 20 ; = #b10100
(fxarithmetic-shift #b101 -2) => 1 ; =#b1
STklos procedure
This is a SRFI-143 procedure that returns the length of the fixnum in bits (that is, the number of bits necessary to represent the number).
(fxlength #b101) => 3
(fxlength #b1101) => 4
(fxlength #b0101) => 3
STklos procedure
This is a SRFI-143 procedure that merge the fixnum bitstrings fx1
and fx2
, with
bitstring mask determining from which string to take each bit. That is, if the kth bit
of mask is 1, then the kth bit of the result is the kth bit of fx1
, otherwise the kth
bit of fx2
.
(fxif 3 1 8) => 9
(fxif 3 8 1) => 0
(fxif 1 1 2) => 3
(fxif #b00111100 #b11110000 #b00001111) => #b00110011
STklos procedure
This is a SRFI-143 procedure that returns #t
if the index
-th bit of
fx
.
(fxbit-set? 1 3) => #t
(fxbit-set? 2 7) => #t
(fxbit-set? 3 6) => #f
(fxbit-set? 5 #b00111100) => #t
STklos procedure
This is a SRFI-143 procedure that sets the index
-th bit if fx
to one if value
is #t
, and to zero if value
is #f
.
(fxcopy-bit 2 3 #t) => 7
(fxcopy-bit 2 7 #f) => 3
(fxcopy-bit 5 #b00111100 #f) => 28 ; = #b00011100
STklos procedure
This is a SRFI-143 procedure that returns the quantity of bits equal to one in
the fixnum fx
(that is, computes its Hamming weight).
(fxbit-count 8) => 1
(fxbit-count 3) => 2
(fxbit-count 7) => 3
(fxbit-count #b00111010) => 4
STklos procedure
This is a SRFI-143 procedure that returns the index of the first (smallest index)
1 bit in bitstring fx
. Returns -1 if fx
contains no 1 bits (i.e., if fx
is zero).
(fxfirst-set-bit 8) => 3
(fxfirst-set-bit 3) => 0
(fxfirst-set-bit 7) => 0
(fxfirst-set-bit #b10110000) => 4
STklos procedure
This is a SRFI-143 procedure that extracts a bit field from the fixnum fx1
.
The bit field is the sequence of bits between start
(including) and end
(excluding)
(fxbit-field #b10110000 3 5) => 6 ; = #b110
STklos procedure
This is a SRFI-143 procedure that returns fx with the field cyclically permuted by count bits towards high-order.
(fxbit-field-rotate #b101011100 -2 1 5) => 342 = #b101010110
(fxbit-field-rotate #b101011011110 -3 2 10) => 3034 = #b101111011010
(fxbit-field-rotate #b101011011110 3 2 10) => 2806 = #b101011110110
STklos procedure
This is a SRFI-143 procedure that returns fx with the order of the bits in the field reversed.
(fxbit-field-reverse #b101011100 1 5) => #b101001110
(fxbit-field-reverse #b101011011110 2 10) => #b101110110110
STklos procedure
Returns two values: i
`j`k
, and carry: it is the value of the computation
(let*-values (((s) (+ i j k))
((q r) (balanced/ s (expt 2 fx-width))))
(values r q))
STklos procedure
Returns two values: i
-j
-k
, and carry: it is the value of the computation
(let*-values (((s) (- i j k))
((q r) (balanced/ s (expt 2 fx-width))))
(values r q))
STklos procedure
Returns two values: i
*j
+k
, and carry: it is the value of the computation
(let*-values (((s) (+ (* i j) k))
((q r) (balanced/ s (expt 2 fx-width))))
(values r q))
4.3. Booleans
Of all the standard Scheme values, only #f
counts as false in
conditional expressions. Except for #f
, all standard Scheme values,
including #t
, pairs, the empty list, symbols, numbers, strings,
vectors, and procedures, count as true.
Boolean constants evaluate to themselves, so they do not need to be quoted in programs.
R5RS procedure
Not returns #t
if obj
is false, and returns #f
otherwise.
(not #t) => #f
(not 3) => #f
(not (list 3)) => #f
(not #f) => #t
(not '()) => #f
(not (list)) => #f
(not 'nil) => #f
R5RS procedure
Boolean?
returns #t
if obj
is either #t
or #f
and returns
#f
otherwise.
(boolean? #f) => #t
(boolean? 0) => #f
(boolean? '()) => #f
R5RS procedure
Returns #t
if all the arguments are booleans and all are #t
or all are #f
.
4.4. Pairs and lists
R5RS procedure
Pair?
returns #t
if obj
is a pair, and otherwise returns #f
.
R5RS procedure
Returns a newly allocated pair whose car is obj1 and whose cdr is obj2. The pair is guaranteed to be different (in the sense of eqv?) from every existing object.
(cons 'a '()) => (a)
(cons '(a) '(b c d)) => ((a) b c d)
(cons "a" '(b c)) => ("a" b c)
(cons 'a 3) => (a . 3)
(cons '(a b) 'c) => ((a b) . c)
R5RS procedure
Returns the contents of the car field of pair.
Note that it is an error to take the car
of the empty list.
(car '(a b c)) => a
(car '((a) b c d)) => (a)
(car '(1 . 2)) => 1
(car '()) => error
R5RS procedure
Returns the contents of the cdr field of pair.
Note that it is an error to take the cdr
of the empty list.
(cdr '((a) b c d)) => (b c d)
(cdr '(1 . 2)) => 2
(cdr '()) => error
R5RS procedure
Stores obj
in the car field of pair
.
The value returned by set-car!
is void.
(define (f) (list 'not-a-constant-list))
(define (g) '(constant-list))
(set-car! (f) 3)
(set-car! (g) 3) => error
R5RS procedure
Stores obj
in the cdr field of pair
.
The value returned by set-cdr!
is void.
R5RS procedure
These procedures are compositions of car
and cdr
, where for example
caddr
could be defined by
(define caddr (lambda (x) (car (cdr (cdr x)))))
Arbitrary compositions, up to four deep, are provided. There are twenty-eight of these procedures in all.
R5RS procedure
Returns #t
if obj
is the empty list, otherwise returns #f
.
STklos procedure
Returns #t
if obj
is a mutable pair, otherwise returns #f
.
(pair-mutable? '(1 . 2)) => #f
(pair-mutable? (cons 1 2)) => #t
(pair-mutable? 12) => #f
R5RS procedure
Returns #t
if obj
is a list, otherwise returns #f
. By definition,
all lists have finite length and are terminated by the empty list.
(list? '(a b c)) => #t
(list? '()) => #t
(list? '(a . b)) => #f
(let ((x (list 'a)))
(set-cdr! x x)
(list? x)) => #f
R7RS procedure
Returns a newly allocated list of k elements. If a second argument is given, then each element is initialized to fill . Otherwise the initial contents of each element is unspecified.
R5RS procedure
Returns a newly allocated list of its arguments.
(list 'a (+ 3 4) 'c) => (a 7 c)
(list) => ()
STklos procedure
list*
is like list
except that the last argument to list*
is
used as the ,(emph "cdr") of the last pair constructed.
(list* 1 2 3) => (1 2 . 3)
(list* 1 2 3 '(4 5)) => (1 2 3 4 5)
(list*) => ()
R5RS procedure
Returns the length of list
.
(length '(a b c)) => 3
(length '(a (b) (c d e))) => 3
(length '()) => 0
R5RS procedure
Returns a list consisting of the elements of the first list followed by the elements of the other lists.
(append '(x) '(y)) => (x y)
(append '(a) '(b c d)) => (a b c d)
(append '(a (b)) '((c))) => (a (b) (c))
The resulting list is always newly allocated, except that it shares structure with the last list argument. The last argument may actually be any object; an improper list results if the last argument is not a proper list.
(append '(a b) '(c . d)) => (a b c . d)
(append '() 'a) => a
STklos procedure
Returns a list consisting of the elements of the first list
followed by the elements of the other lists.
Contrarily to append
, the parameter lists (except the last one) are
physically modified: their last pair is changed to the value of the next
list in the append!
formal parameter list.
(let* ((l1 (list 1 2))
(l2 (list 3))
(l3 (list 4 5))
(l4 (append! l1 l2 l3)))
(list l1 l2 l3 l4)) => ((1 2 3 4 5) (3 4 5) (4 5) (1 2 3 4 5))
An error is signaled if one of the given lists is a constant list.
R5RS procedure
Returns a newly allocated list consisting of the elements of list
in
reverse order.
(reverse '(a b c)) => (c b a)
(reverse '(a (b c) d (e (f)))) => ((e (f)) d (b c) a)
STklos procedure
Returns a list consisting of the elements of list
in reverse order.
Contrarily to reverse
, the returned value is not newly allocated but
computed "in place".
(let ((l '(a b c)))
(list (reverse! l) l)) => ((c b a) (a))
(reverse! '(a constant list)) => error
R5RS procedure
Returns the sublist of list
obtained by omitting the first k
elements.
It is an error if list has fewer than k
elements. List-tail could
be defined by
(define list-tail
(lambda (x k)
(if (zero? k)
x
(list-tail (cdr x) (- k 1)))))
STklos procedure
Returns the last pair of list
.
(last-pair '(1 2 3)) => (3)
(last-pair '(1 2 . 3)) => (2 . 3)
R5RS procedure
Returns the k`th element of `list
. (This is the same as the car
of (list-tail list k)
.) It is an error if list has fewer than k
elements.
(list-ref '(a b c d) 2) => c
(list-ref '(a b c d)
(inexact->exact (round 1.8))) => c
R7RS procedure
The list-set!
procedure stores obj
in element k
of list
.
It is an error if k
is not a valid index of list
.
(let ((ls (list 'one 'two 'five!)))
(list-set! ls 2 'three)
ls) => (one two three)
(list-set! '(0 1 2) 1 "oops") => error (constant list)
R5RS / R7RS procedure
These procedures return the first sublist of list whose car is obj
,
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
uses eq?
to compare obj with the elements of list,
while memv
uses eqv?
and member
uses compare
, if given, and
equal?
otherwise.
(memq 'a '(a b c)) => (a b c)
(memq 'b '(a b c)) => (b c)
(memq 'a '(b c d)) => #f
(memq (list 'a) '(b (a) c)) => #f
(member (list 'a)
'(b (a) c)) => ((a) c)
(member "B"
’("a" "b" "c")
string-ci=?) => ("b" "c")
(memv 101 '(100 101 102)) => (101 102)
As in R7RS, the member function accepts also a
comparison function.
|
R5RS / R7RS procedure
Alist
(for "association list") must be a list of pairs. These procedures
find the first pair in alist
whose car field is obj
, and returns that
pair. If no pair in alist
has obj
as its car, then #f
(not the empty
list) is returned. Assq
uses eq?
to compare obj
with the car fields
of the pairs in alist
, while assv
uses eqv?
and assoc
uses equal?
.
(define e '((a 1) (b 2) (c 3)))
(assq 'a e) => (a 1)
(assq 'b e) => (b 2)
(assq 'd e) => #f
(assq (list 'a) '(((a)) ((b)) ((c))))
=> #f
(assoc (list 'a) '(((a)) ((b)) ((c))))
=> ((a))
(assoc 2.0 '((1 1) (2 4) (3 9)) =)
=> (2 4)
(assv 5 '((2 3) (5 7) (11 13)))
=> (5 7)
Although they are ordinarily used as predicates,
memq , memv , member , assq , assv , and assoc do not have question
marks in their names because they return useful values rather than just
#t or #f .
|
As in R7RS, the assoc function accepts also a
comparison function.
|
R7RS procedure
list-copy
recursively copies trees of pairs. If obj
is
not a pair, it is returned; otherwise the result is a new pair whose
car
and cdr
are obtained by calling list-copy
on
the car
and cdr
of obj
, respectively.
STklos procedure
Filter
returns all the elements of list
that satisfy predicate
pred
. The list
is not disordered: elements that appear in the
result list occur in the same order as they occur in the argument
list. Filter!
does the same job as filter
by physically
modifying its list
argument
(filter even? '(0 7 8 8 43 -4)) => (0 8 8 -4)
(let* ((l1 (list 0 7 8 8 43 -4))
(l2 (filter! even? l1)))
(list l1 l2)) => ((0 8 8 -4) (0 8 8 -4))
An error is signaled if list
is a constant list.
STklos procedure
Remove
returns list
without the elements that satisfy predicate pred
:
The list is not disordered — elements that appear in the result list occur
in the same order as they occur in the argument list. Remove!
does the
same job than remove
by physically modifying its list
argument
(remove even? '(0 7 8 8 43 -4)) => (7 43)
STklos procedure
Delete
uses the comparison procedure =
, which defaults to
equal?
, to find all elements of list
that are equal to x
, and
deletes them from list
. The dynamic order in which the various
applications of =
are made is not specified.
The list is not disordered — elements that appear in the result list occur in the same order as they occur in the argument list.
The comparison procedure is used in this way: (= x ei)
. That is,
x
is always the first argument, and a list element is always the
second argument. The comparison procedure will be used to compare
each element of list exactly once; the order in which it is applied
to the various ei
is not specified. Thus, one can reliably remove
all the numbers greater than five from a list with
(delete 5 list <)
delete!
is the linear-update variant of delete
. It is allowed,
but not required, to alter the cons cells in its argument list
to
construct the result.
4.5. Symbols
The STklos reader can read symbols whose names contain special
characters or letters in the non standard case. When a symbol is
read, the parts enclosed in bars |
will be entered
verbatim into the symbol’s name. The |
characters are not
part of the symbol; they only serve to delimit the sequence of
characters that must be entered "as is". In order to maintain
read-write invariance, symbols containing such sequences of special
characters will be written between a pair of |
.
In addition, any character can be used within an identifier when
specified via an inline hex escape . For example, the identifier
Hx65;llo
is the same as the identifier Hello, and, if the
UTF-8 encoding is used, the identifier x3BB;
is the same as
the identifier λ
.
'|a| => a
(string->symbol "a") => |A|
(symbol->string '|A|) => "A"
'|a b| => |a b|
'a|B|c => |aBc|
(write '|FoO|) |- |FoO|
(display '|FoO|) |- FoO
R5RS procedure
Returns #t
if obj is a symbol, otherwise returns #f
.
(symbol? 'foo) => #t
(symbol? (car '(a b))) => #t
(symbol? "bar") => #f
(symbol? 'nil) => #t
(symbol? '()) => #f
(symbol? #f) => #f
(symbol? :key) => #f
R5RS procedure
Returns #t
if all the arguments are symbols and all have the same name in
the sense of string=?
.
R5RS procedure
Returns the name of symbol
as a string. If the symbol was part of an
object returned as the value of a literal expression or by a call to the
read
procedure, and its name contains alphabetic characters, then the
string returned will contain characters in the implementation’s preferred
standard case — STklos prefers lower case. If the symbol was returned
by string→symbol
, the case of characters in the string returned will be
the same as the case in the string that was passed to string→symbol
. It
is an error to apply mutation procedures like string-set!
to strings
returned by this procedure.
(symbol->string 'flying-fish) => "flying-fish"
(symbol->string 'Martin) => "martin"
(symbol->string (string->symbol "Malvina"))
=> "Malvina"
R5RS procedure
Returns the symbol whose name is string
. This procedure can create
symbols with names containing special characters or letters in the
non-standard case, but it is usually a bad idea to create such symbols
because in some implementations of Scheme they cannot be read as themselves.
(string->symbol "mISSISSIppi") => |mISSISSIppi|
(eq? 'bitBlt (string->symbol "bitBlt")) => #f
(eq? 'JollyWog
(string->symbol
(symbol->string 'JollyWog))) => #t
(string=? "K. Harper, M.D."
(symbol->string
(string->symbol "K. Harper, M.D."))) => #t
The expression (eq? 'mISSISSIppi 'mississippi) returns #f if
STklos is running in case-sensitive mode (default), whereas it returns
#t otherwise.
|
STklos procedure
Returns the symbol whose print name is made from the characters of
string
. This symbol is guaranteed to be unique (i.e. not
eq?
to any other symbol):
(let ((ua (string->uninterned-symbol "a")))
(list (eq? 'a ua)
(eqv? 'a ua)
(eq? ua (string->uninterned-symbol "a"))
(eqv? ua (string->uninterned-symbol "a"))))
=> (#f #t #f #t)
STklos procedure
Creates a new symbol. The print name of the generated symbol
consists of a prefix (which defaults to "G") followed by the decimal
representation of a number. If prefix
is specified, it must be
either a string or a symbol.
(gensym) => |G100|
(gensym "foo-") => foo-101
(gensym 'foo-) => foo-102
4.6. Characters
The following table gives the list of allowed character names with their ASCII eqivalent expressed in octal. Some chracaters have an alternate name which is also shown in this table.
name | value | alt. name | name | value | alt. name |
---|---|---|---|---|---|
nul |
000 |
null |
soh |
001 |
|
stx |
002 |
etx |
003 |
||
eot |
004 |
enq |
005 |
||
ack |
006 |
bel |
007 |
alarm |
|
bs |
010 |
backspace |
ht |
011 |
tab |
nl |
012 |
newline |
vt |
013 |
|
np |
014 |
page |
cr |
015 |
return |
so |
016 |
si |
017 |
||
dle |
020 |
dc1 |
021 |
||
dc2 |
022 |
dc3 |
023 |
||
dc4 |
024 |
nak |
025 |
||
syn |
026 |
etb |
027 |
||
can |
030 |
em |
031 |
||
sub |
032 |
esc |
033 |
escape |
|
fs |
034 |
gs |
035 |
||
rs |
036 |
us |
037 |
||
sp |
040 |
space |
del |
177 |
delete |
STklos supports the complete Unicode character set, if UTF-8 encoding is used. Hereafter, are some examples of characters:
#A => uppercase A
#a => lowercase a
#x41 => the U+0041 character (uppercase A)
#x03bb => λ
R5RS procedure
Returns #t
if obj
is a character, otherwise returns #f
.
R5RS procedure
These procedures impose a total ordering on the set of characters. It is guaranteed that under this ordering:
-
The upper case characters are in order.
-
The lower case characters are in order.
-
The digits are in order.
-
Either all the digits precede all the upper case letters, or vice versa.
-
Either all the digits precede all the lower case letters, or vice versa. )
R5RS procedure
These procedures are similar to char=?
et cetera, but they treat
upper case and lower case letters as the same. For example,
(char-ci=? #A #a)
returns #t
.
R5RS procedure
These procedures return #t
if their arguments are alphabetic, numeric,
whitespace, upper case, or lower case characters, respectively, otherwise they
return #f
. The following remarks, which are specific to the ASCII character
set, are intended only as a guide: The alphabetic characters are the 52
upper and lower case letters. The numeric characters are the ten decimal
digits. The whitespace characters are space, tab, line feed, form feed,
and carriage return.
R5RS procedure
Given a character, char→integer
returns an exact integer
representation of the character. Given an exact integer that is the
image of a character under char→integer
, integer→char
returns
that character. These procedures implement order-preserving
isomorphisms between the set of characters under the char⇐?
ordering and some subset of the integers under the ⇐
ordering. That is, if
(char<=? a b) => #t and (<= x y) => #t
and x and y are in the domain of integer→char
, then
(<= (char->integer a)
(char->integer b)) => #t
(char<=? (integer->char x)
(integer->char y)) => #t
integer→char
accepts an exact number between 0 and #xD7FFF or between
#xE000 and #x10FFFF, if UTF8 encoding is used. Otherwise, it accepts a
number between 0 and #xFF.
R5RS procedure
These procedures return a character char2
such that
(char-ci=? char char2)
. In addition, if char is alphabetic, then the
result of char-upcase
is upper case and the result of char-downcase
is
lower case.
STklos procedure
This procedure applies the Unicode simple case folding algorithm and returns the result. Note that language-sensitive folding is not used. If the argument is an uppercase letter, the result will be either a lowercase letter or the same as the argument if the lowercase letter does not exist.
R7RS procedure
This procedure returns the numeric value (0 to 9) of its argument if it is a numeric digit (that is, if char-numeric? returns #t), or #f on any other character.
(digit-value
(digit-value #3) => 3
(digit-value #x0664) => 4
(digit-value #x0AE6) => 0
(digit-value #x0EA6) => #f
4.7. Strings
STklos string constants allow the insertion of arbitrary characters by encoding them as escape sequences. An escape sequence is introduced by a backslash "$backslash$". The valid escape sequences are shown in the following table.
Sequence | Character inserted |
---|---|
a |
Alarm |
b |
Backspace |
e |
Escape |
n |
Newline |
t |
Horizontal Tab |
r |
Carriage Return |
" |
doublequote U+0022 |
\ |
backslash U+005C |
0abc |
ASCII character with octal value abc |
x<hexa value>; |
ASCII character with given hexadecimal value |
<intraline whitespace><newline><intraline whitespace> |
None (permits to enter a string on several lines) |
<other> |
<other> |
For instance, the string
"ab040x20;cnd
e"
is the string consisting of the characters
#a
, #b
, #space
, #space
,
#c
, #newline
, #d
and #e
.
Notes:
-
Using octal code is limited to characters in the range 0 to #xFF. It is then not convenient to enter Unicode characters. This form is deprecated should not be used anymore.
-
A line ending which is preceded by <intraline whitespace> expands to nothing (along with any trailing <intraline whitespace>), and can be used to indent strings for improved legibility.
R5RS procedure
Returns #t
if obj
is a string, otherwise returns #f
.
R5RS procedure
Make-string
returns a newly allocated string of length k
. If char
is
given, then all elements of the string are initialized to char
, otherwise
the contents of the string are unspecified.
R5RS procedure
Returns a newly allocated string composed of the arguments.
R5RS procedure
Returns the number of characters in the given string
.
R5RS procedure
String-ref
returns character k of string using zero-origin indexing
(k
must be a valid index of string).
R5RS procedure
String-set!
stores char
in element k
of string
and returns
void (k
must be a valid index of string
).
(define (f) (make-string 3 #*))
(define (g) "***")
(string-set! (f) 0 #?) => void
(string-set! (g) 0 #?) => error
(string-set! (symbol->string 'immutable) 0 #?)
=> error
R5RS / R7RS procedure
Returns #t
if all the strings are the same length and contain the same
characters in the same positions, otherwise returns #f
. String-ci=?
treats upper and lower case letters as though they were the same character,
but string=?
treats upper and lower case as distinct characters.
R5RS version of these functions accept only two arguments. |
R5RS / R7RS procedure
These procedures are the lexicographic extensions to strings of the
corresponding orderings on characters. For example, string<?
is the
lexicographic ordering on strings induced by the ordering char<?
on
characters. If two strings differ in length but are the same up to the
length of the shorter string, the shorter string is considered to be
lexicographically less than the longer string.
R5RS version of these functions accept only two arguments. |
R5RS procedure
String
must be a string, and start
and end
must be exact integers
satisfying
0 <= start <= end <= (string-length string).
Substring
returns a newly allocated string formed from the characters
of string
beginning with index start
(inclusive) and ending with
index end
(exclusive).
R5RS procedure
Returns a newly allocated string whose characters form the concatenation of the given strings.
R5RS / R7RS procedure
String→list
returns a newly allocated list of the characters of
string
between start
and end
. List→string
returns a newly
allocated string formed from the characters in the list list
,
which must be a list of characters. String→list
and
list→string
are inverses so far as equal?
is concerned.
The R5RS version of string→list accepts only one
parameter.
|
R5RS / R7RS procedure
Returns a newly allocated copy of the part of the given string
between start
and stop
.
The R5RS version of string-copy accepts only one argument.
|
R7RS procedure
Copies the characters of string
from between start
and end
to string to
, starting at at
. The order in which characters are copied
is unspecified, except that if the source and destination overlap,
copying takes place as if the source is first copied into a temporary
string and then into the destination. This can be achieved without
allocating storage by making sure to copy in the correct direction in
such circumstances.
It is an error if at
is less than zero or greater than the length
of to
. It is also an error if (- (string-length to) at)
is less
than (- end start)
.
STklos procedure
Parses string
and returns a list of tokens ended by a character of the
delimiters
string. If delimiters
is omitted, it defaults to a string
containing a space, a tabulation and a newline characters.
(string-split "/usr/local/bin" "/")
=> ("usr" "local" "bin")
(string-split "once upon a time")
=> ("once" "upon" "a" "time")
STklos procedure
Returns the (first) index where str1
is a substring of str2
if it exists;
otherwise returns #f
.
(string-position "ca" "abracadabra") => 4
(string-position "ba" "abracadabra") => #f
This function was also called string-index . This name is deprecated
since it conficts with the string-index defined in SRFI-13.
|
STklos procedure
Returns #t
if str1
appears somewhere in str2
; otherwise returns #f
.
R7RS procedure
Stores char
in every element of the given string
between start
and end
.
The R5RS version of string-fill! accepts only one argument.
|
STklos procedure
This function places the characters of string s2
in the string s1
starting at position offset
. The result of string-blit!
may modify
the string s1
. Note that the characters of s2
can be written after
the end of s1
(in which case a new string is allocated).
(string-blit! (make-string 6 #X) "abc" 2)
=> "XXabcX"
(string-blit! (make-string 10 #X) "abc" 5)
=> "XXXXXabcXX"
(string-blit! (make-string 6 #X) "a" 10)
=> "XXXXXX0000a"
STklos procedure
Returns #t
if obj
is a mutable string, otherwise returns #f
.
(string-mutable? "abc") => #f
(string-mutable? (string-copy "abc")) => #t
(string-mutable? (string #a #b #c)) => #t
(string-mutable? 12) => #f
The following string primitives are compatible with SRFI-13 (String Library) and their documentation comes from the SRFI document.
Notes:
-
The string SRFI is supported by STklos. The function listed below just don’t need to load the full SRFI to be used
-
The functions
string-upcase
,string-downcase
andstring-foldcase
are also defined in R7RS.
R7RS procedure
Returns a string in which the upper case letters of string str
between the
start
and end
indices have been replaced by their lower case equivalent.
If start
is omited, it defaults to 0. If end
is omited, it defaults to
the length of str
.
(string-downcase "Foo BAR") => "foo bar"
(string-downcase "Foo BAR" 4) => "bar"
(string-downcase "Foo BAR" 4 6) => "ba"
In R7RS, string-downcase accepts only one argument.
|
STklos procedure
This is the in-place side-effecting variant of string-downcase
.
(string-downcase! (string-copy "Foo BAR") 4) => "Foo bar"
(string-downcase! (string-copy "Foo BAR") 4 6) => "Foo baR"
R7RS procedure
Returns a string in which the lower case letters of string str
between the
start
and end
indices have been replaced by their upper case equivalent.
If start
is omited, it defaults to 0. If end
is omited, it defaults to
the length of str
.
In R7RS, string-upcase accepts only one argument.
|
STklos procedure
This is the in-place side-effecting variant of string-upcase
.
STklos procedure
This function returns a string. For every character c
in the
selected range of str
, if c
is preceded by a cased character, it
is downcased; otherwise it is titlecased. If start
is omited, it
defaults to 0. If end
is omited, it defaults to the length of str
.
Note that if a start
index is specified, then the character preceding
s[start]
has no effect on the titlecase decision for character s[start]
.
(string-titlecase "--capitalize tHIS sentence.")
=> "--Capitalize This Sentence."
(string-titlecase "see Spot run. see Nix run.")
=> "See Spot Run. See Nix Run."
(string-titlecase "3com makes routers.")
=> "3Com Makes Routers."
(string-titlecase "greasy fried chicken" 2)
=> "Easy Fried Chicken"
STklos procedure
This is the in-place side-effecting variant of string-titlecase
.
STklos procedure
Extends string by appending each value (in order) to the end of string. A value can be a character or a string.
It is guaranteed that string-append! will return the same object that was passed to it as first argument, whose size may be larger.
This function is defined in SRFI-118. |
STklos procedure
Replaces the characters of the variable-size string dst (between dst-start and dst-end) with the characters of the string src (between src-start and src-end). The number of characters from src may be different from the number replaced in dst, so the string may grow or contract. The special case where dst-start is equal to dst-end corresponds to insertion; the case where src-start is equal to src-end corresponds to deletion. The order in which characters are copied is unspecified, except that if the source and destination overlap, copying takes place as if the source is first copied into a temporary string and then into the destination. Returns string, appended with the characters form the concatenation of the given arguments, which can be either strings or characters.
It is guaranteed that string-replace! will return the same object that was passed to it as first argument, whose size may be larger.
This function is defined in SRFI-118. |
R7RS procedure
Returns a string in which the Unicode simple case-folding algorithm has
been applied on str
between the start
and end
indices.
If start
is omited, it defaults to 0. If end
is omited, it defaults to
the length of str
.
In R7RS, string-foldcase accepts only one argument.
|
STklos procedure
This is the in-place side-effecting variant of string-foldcase
.
4.8. Vectors
Vectors are heterogenous structures whose elements are indexed by integers. A vector typically occupies less space than a list of the same length, and the average time required to access a randomly chosen element is typically less for the vector than for the list.
The length of a vector is the number of elements that it contains. This number is a non-negative integer that is fixed when the vector is created. The valid indexes of a vector are the exact non-negative integers less than the length of the vector. The first element in a vector is indexed by zero, and the last element is indexed by one less than the length of the vector.
Vectors are written using the notation #(obj …)
.
For example, a vector of length 3 containing the number zero in
element 0, the list (2 2 2 2)
in element 1, and the
string "Anna"
in element 2 can be written as
following:
#(0 (2 2 2 2) "Anna")
In STklos, vectors constants don’t need to be quoted. |
R5RS procedure
Returns #t
if obj
is a vector, otherwise returns #f
.
R5RS procedure
Returns a newly allocated vector of k
elements. If a second argument is
given, then each element is initialized to fill
. Otherwise, the initial
contents of each element is unspecified.
R5RS procedure
Returns a newly allocated vector whose elements contain the given arguments.
Analogous to list
.
(vector 'a 'b 'c) => #(a b c)
R5RS procedure
Returns the number of elements in vector
as an exact integer.
R5RS procedure
k
must be a valid index of vector
. Vector-ref
returns the contents of
element k
of vector.
(vector-ref '#(1 1 2 3 5 8 13 21)
5) => 8
(vector-ref '#(1 1 2 3 5 8 13 21)
(let ((i (round (* 2 (acos -1)))))
(if (inexact? i)
(inexact->exact i)
i))) => 13
R5RS procedure
k
must be a valid index of vector
. Vector-set!
stores obj
in element
k
of vector
. The value returned by vector-set!
is void.
(let ((vec (vector 0 '(2 2 2 2) "Anna")))
(vector-set! vec 1 '("Sue" "Sue"))
vec) => #(0 ("Sue" "Sue") "Anna")
(vector-set! '#(0 1 2) 1 "doe") => error ; constant vector
R5RS / R7RS procedure
Vector→list
returns a newly allocated list of the objects contained in
the elements of vector
between start an end. List→vector
returns a
newly created vector initialized to the elements of the list list
.
In both procedures, order is preserved.
(vector->list '#(dah dah didah)) => (dah dah didah)
(vector->list '#(dah dah didah) 1 2) => (dah)
(list->vector '(dididit dah)) => #(dididit dah)
The R5RS version of vector→list accepts only one
parameter.
|
R7RS procedure
The vector→string
procedure returns a newly allocated
string of the objects contained in the elements of vector
between start
and end
. It is an error if any element of vector
between start
and end
is not a character.
The string→vector
procedure returns a newly created vector
initialized to the elements of string
between start
and end
.
In both procedures, order is preserved.
(string->vector "ABC") => #(#A #B #C)
(vector->string #(#1 #2 #3)) => "123"
R5RS procedure
Returns a newly allocated vector whose elements are the concatenation of the elements of the given vectors.
(vector-append #(a b c) #(d e f)) => #(a b c d e f)
R5RS / R7RS procedure
Stores fill
in every element of vector
between start
and end
.
The R5RS version of vector-fill! accepts only one
parameter.
|
R5RS / R7RS procedure
Return a newly allocated copy of the elements of the given
vector between start
and end
. The elements of the new
vector are the same (in the sense of eqv?) as the elements
of the old.
Note that, if v
is a constant vector, its copy is not constant.
(define a #(1 8 2 8)) ; a is immutable
(define b (vector-copy a)) ; b is mutable
(vector-set! b 0 3)
b => #(3 8 2 8)
(define c (vector-copy b 1 3))
c => #(8 2)
R7RS procedure
STklos procedure
Returns a copy of v of the given size
. If size
is greater
than the vector size of v
, the contents of the newly allocated vector cells
is set to the value of fill
. If fill
is omitted the content of the
new cells is void.
STklos procedure
Returns #t
if obj
is a mutable vector, otherwise returns #f
.
(vector-mutable? '#(1 2 a b)) => #f
(vector-mutable? (vector-copy '#(1 2))) => #t
(vector-mutable? (vector 1 2 3)) => #t
(vector-mutable? 12) => #f
STklos procedure
Obj
must be a list or a vector. Sort
returns a copy of obj
sorted
according to predicate
. Predicate
must be a procedure which takes
two arguments and returns a true value if the first argument is strictly
``before'' the second.
(sort '(1 2 -4 12 9 -1 2 3) <)
=> (-4 -1 1 2 2 3 9 12)
(sort '#("one" "two" "three" "four")
(lambda (x y) (> (string-length x) (string-length y))))
=> '#("three" "four" "one" "two")
4.9. Structures
A structure type is a record data type composing a number of slots. A structure, an instance of a structure type, is a first-class value that contains a value for each field of the structure type.
Structures can be created with the define-struct
high
level syntax. However, STklos also offers some low-level functions
to build and access the internals of a structure.
STklos syntax
Defines a structure type whose name is <name>
. Once a structure type is
defined, the following symbols are bound:
-
<name>
denotes the structure type. -
make-<name>
is a procedure which takes 0 ton
parameters (if there aren
slots defined). Each parameter is assigned to the corresponding field (in the definition order). -
<name>?
is a predicate which returns#t
when applied to an instance of the<name>
structure type and#f
otherwise -
<name>-<slot>
(one for each defined<slot>
) to read the content of an instance of the<name>
structure type. Writting the content of a slot can be done using a generalizedset!
.
(define-struct point x y)
(define p (make-point 1 2))
(point? p) => #t
(point? 100) => #f
(point-x p) => 1
(point-y p) => 2
(set! (point-x p) 10)
(point-x p) => 10
STklos procedure
This form which is more general than define-struct
permits to define a
new structure type whose name is name
. Parent is the structure
type from which is the new structure type is a subtype (or #f
is the
new structure-type has no super type). Slots
is the list of the slot
names which constitute the structure tpe.
When a structure type is s subtype of a previous type, its slots are added to the ones of the super type.
STklos procedure
Returns #t
if obj
is a structure type, otherwise returns #f
.
(let ((type (make-struct-type 'point #f '(x y))))
(struct-type? type)) => #t
STklos procedure
Returns the slots of the structure type structype
as a list.
(define point (make-struct-type 'point #f '(x y)))
(define circle (make-struct-type 'circle point '(r)))
(struct-type-slots point) => (x y)
(struct-type-slots circle) => (x y r)
STklos procedure
Returns the super type of the structure type structype
, if it exists
or #f
otherwise.
STklos procedure
Returns the name associated to the structure type structype
.
STklos procedure
Change the default writer associated to structures of type structype
to the proc
procedure. The proc
procedure must accept 2 arguments
(the structure to write and the port wher the structure must be written
in that order). The value returned by struct-type-change-writer!
is the
old writer associated to structype
. To restore the standard structure
writer for structype
, use the special value #f
.
(define point (make-struct-type 'point #f '(x y)))
(struct-type-change-writer!
point
(lambda (s port)
(let ((type (struct-type s)))
(format port "{~A" (struct-type-name type))
;; display the slots and their value
(for-each (lambda (x)
(format port " ~A=~S" x (struct-ref s x)))
(struct-type-slots type))
(format port "}"))))
(display (make-struct point 1 2)) |- {point x=1 y=2}
STklos procedure
Returns a newly allocated instance of the structure type structype
,
whose slots are initialized to expr
… If fewer expr
than the number of
instances are given to make-struct
, the remaining slots are inialized with
the special void value.
STklos procedure
Returns #t
if obj
is a structure, otherwise returns #f
.
(let* ((type (make-struct-type 'point #f '(x y)))
(inst (make-struct type 1 2)))
(struct? inst)) => #t
STklos procedure
Returns the structure type of the s
structure
STklos procedure
Returns the value associated to slot slot-name
of the s
structure.
(define point (make-struct-type 'point #f '(x y)))
(define circle (make-struct-type 'circle point '(r)))
(define p (make-struct point 1 2))
(define c (make-struct circle 10 20 30))
(struct-ref p 'y) => 2
(struct-ref c 'r) => 30
STklos procedure
Stores value in the to slot slot-name
of the s
structure. The value
returned by struct-set!
is void.
(define point (make-struct-type 'point #f '(x y)))
(define p (make-struct point 1 2))
(struct-ref p 'x) => 1
(struct-set! p 'x 0)
(struct-ref p 'x) => 0
STklos procedure
Return a boolean that indicates if the structure s
is of type structype
.
Note that if s
is an instance of a subtype of S, it is considered
also as an instance of type S.
(define point (make-struct-type 'point #f '(x y)))
(define circle (make-struct-type 'circle point '(r)))
(define p (make-struct point 1 2))
(define c (make-struct circle 10 20 30))
(struct-is-a? p point) => #t
(struct-is-a? c point) => #t
(struct-is-a? p circle) => #f
(struct-is-a? c circle) => #t
STklos procedure
Returns the content of structure s
as an A-list whose keys are the
slots of the structure type of s
.
(define point (make-struct-type 'point #f '(x y)))
(define p (make-struct point 1 2))
(struct->list p) => ((x . 1) (y . 2))
4.10. Bytevectors
Bytevectors represent blocks of binary data. They
are fixed-length sequences of bytes, where a byte is an
exact integer in the range (0, 255)
. 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.
R7RS procedure
Returns #t
if obj
is a bytevector and returns #f
otherwise.
R7RS procedure
Returns a newly allocated bytevector of k bytes. If If byte
is given,
then all elements of the bytevector are initialized to byte
, otherwise
the contents of each element is 0.
(make-bytevector 2 12) => #u8(12 12)
(make-bytevector 3) => #u8(0 0 0)
R7RS procedure
Returns a newly allocated bytevector containing its arguments.
(bytevector 1 3 5 1 3 5) => #u8(1 3 5 1 3 5)
(bytevector) => #u8()
R7RS procedure
Returns the length of bytevector
in bytes as an exact integer.
R7RS procedure
Returns the byte at index k
of bytevector
as an exact integer in the
range [0..255]. It is an error if k
is not a valid index of bytevector
.
(bytevector-u8-ref #u8(1 1 2 3 5 8 13 21) 5) => 8
STklos procedure
Stores byte as the k th byte of bytevector. It is an error if k
is not a valid index of bytevector
.
(let ((bv (bytevector 1 2 3 4)))
(bytevector-u8-set! bv 1 3)
bv) => #u8(1 3 3 4)
R7RS procedure
Returns a newly allocated bytevector containing the bytes in bytevector
between start
and end
.
(define a #u8(1 2 3 4 5))
(bytevector-copy a 2 4)) => #u8(3 4)
R7RS procedure
Copies the bytes of bytevector from
between start
and end
to bytevector to
, starting at at
. The order in which bytes
are copied is unspecified, except that if the source and
destination overlap, copying takes place as if the source is first
copied into a temporary bytevector and then into the destination.
This can be achieved without allocating storage by making sure
to copy in the correct direction in such circumstances.
It is an error if at
is less than zero or greater than the length
of to
. It is also an error if (- (bytevector-length to) at)
is
less than (- end start)
.
(define a (bytevector 1 2 3 4 5))
(define b (bytevector 10 20 30 40 50))
(bytevector-copy! b 1 a 0 2)
b => #u8(10 1 2 40 50
R5RS procedure
Returns a newly allocated bytevector whose elements are the concatenation of the elements in the given bytevectors.
(bytevector-append #u8(0 1 2) #u8(3 4 5))
=> #u8(0 1 2 3 4 5)
R7RS procedure
These procedures translate between strings and bytevectors
that encode those strings using the UTF-8 encoding.
The utf8→string
procedure decodes the bytes of
a bytevector between start
and end
and returns the
corresponding string; the string→utf8
procedure encodes the
characters of a string between start
and end
and returns
the corresponding bytevector.
It is an error for bytevector
to contain invalid UTF-8 byte
sequences.
(utf8->string #u8(#x41)) => "A"
(string->utf8 "λ") => #u8((#xce #xbb)
4.11. Control features
R5RS procedure
Returns #t
if obj
is a procedure, otherwise returns #f
.
(procedure? car) => #t
(procedure? 'car) => #f
(procedure? (lambda (x) (* x x))) => #t
(procedure? '(lambda (x) (* x x))) => #f
(call-with-current-continuation procedure?) => #t
R5RS procedure
Proc
must be a procedure and args
must be a list. Calls proc
with the
elements of the list
(append (list arg1 ...) args)
as the actual arguments.
(apply + (list 3 4)) => 7
(define compose
(lambda (f g)
(lambda args
(f (apply g args)))))
((compose sqrt *) 12 75) => 30
R5RS procedure
The list`s must be lists, and `proc
must be a procedure taking as many
arguments as there are lists and returning a single value.
If more than one list is given, then they must all be the same length.
Map
applies proc
element-wise to the elements of the `list`s and returns
a list of the results, in order. The dynamic order in which proc is applied
to the elements of the lists is unspecified.
(map cadr '((a b) (d e) (g h))) => (b e h)
(map (lambda (n) (expt n n))
'(1 2 3 4 5)) => (1 4 27 256 3125)
(map + '(1 2 3) '(4 5 6)) => (5 7 9)
(let ((count 0))
(map (lambda (ignored)
(set! count (+ count 1))
count)
'(a b))) => (1 2) ,(emph "or") (2 1)
R7RS procedure
The strings
must be strings, and proc
must be a procedure taking as
many arguments as there are strings and returning a single
value. If more than one string is given and not all strings have the
same length, string-map
terminates when the shortest list runs
out. String-map
applies proc
element-wise to the elements of the
strings and returns a string of the results, in order. The dynamic
order in which proc is applied to the elements of the strings
is
unspecified.
(string-map char-downcase "AbdEgH")
=> "abdegh"
(string-map
(lambda (c)
(integer->char (+ 1 (char->integer c))))
"HAL")
=> "IBM"
(string-map (lambda (c k)
(if (eqv? k #u)
(char-upcase c)
(char-downcase c)))
"studlycaps"
"ululululul")
=> "StUdLyCaPs"
R7RS procedure
The vectors
must be vectors, and proc
must be a procedure
taking as many arguments as there are vectors and returning a single
value. If more than one vector is given and not all vectors have the
same length, vector-map
terminates when the shortest list runs
out. Vector-map
applies proc
element-wise to the elements of the
vectors and returns a vector of the results, in order. The dynamic
order in which proc is applied to the elements of the vectors
is
unspecified.
(vector-map cadr '#((a b) (d e) (g h)))
=> #(b e h)
(vector-map (lambda (n) (expt n n))
'#(1 2 3 4 5))
=> #(1 4 27 256 3125)
(vector-map + '#(1 2 3) '#(4 5 6))
=> #(5 7 9)
(let ((count 0))
(vector-map
(lambda (ignored)
(set! count (+ count 1))
count)
'#(a b)))
=> #(1 2) or #(2 1)
R5RS procedure
The arguments to for-each
are like the arguments to map
, but for-each
calls proc for its side effects rather than for its values.
Unlike map
, for-each
is guaranteed to call proc on the elements of
the lists in order from the first element(s) to the last, and the value
returned by for-each
is void.
(let ((v (make-vector 5)))
(for-each (lambda (i)
(vector-set! v i (* i i)))
'(0 1 2 3 4))
v) => #(0 1 4 9 16)
R7RS procedure
The arguments to string-for-each
are like the arguments to
string-map
, but string-for-each
calls proc
for its side effects
rather than for its values. Unlike string-map
, string-for-each
is
guaranteed to call proc
on the elements of the lists in order from
the first element(s) to the last, and the value returned by
string-for-each
is unspecified. If more than one string is given and
not all strings have the same length, string-for-each
terminates when
the shortest string runs out.
(let ((v (list)))
(string-for-each (lambda (c) (set! v (cons (char->integer c) v)))
"abcde")
v)
=> (101 100 99 98 97)
R7RS procedure
The arguments to vector-for-each
are like the arguments to
vector-map
, but vector-for-each
calls proc
for its side effects
rather than for its values. Unlike vector-map
, vector-for-each
is
guaranteed to call proc
on the elements of the lists in order from
the first element(s) to the last, and the value returned by
vector-for-each
is unspecified. If more than one vector is given and
not all vectors have the same length, vector-for-each
terminates when
the shortest vector runs out.
(let ((v (make-vector 5)))
(vector-for-each (lambda (i) (vector-set! v i (* i i)))
'#(0 1 2 3 4))
v)
=> #(0 1 4 9 16)
STklos procedure
every
applies the predicate pred
across the lists, returning true if
the predicate returns true on every application.
If there are n list arguments list1
… listn
, then pred
must be
a procedure taking n arguments and returning a boolean result.
every
applies pred to the first elements of the listi
parameters. If
this application returns false, every immediately returns #f
.
Otherwise, it iterates, applying pred
to the second elements of the listi
parameters, then the third, and so forth. The iteration stops when a
false value is produced or one of the lists runs out of values.
In the latter case, every
returns the true value produced by its final
application of pred. The application of pred to the last element of the
lists is a tail call.
If one of the listi
has no elements, every
simply returns #t
.
Like any
, every’s name does not end with a question mark — this is to
indicate that it does not return a simple boolean (
#t` or #f
), but a
general value.
STklos procedure
any
applies the predicate across the lists, returning true if the
predicate returns true on any application.
If there are n list arguments list1
… listn
, then pred
must be
a procedure taking n arguments.
any
applies pred
to the first elements of the listi
parameters. If
this application returns a true value, any
immediately returns that value.
Otherwise, it iterates, applying pred
to the second elements of the listi
parameters, then the third, and so forth. The iteration stops when a true
value is produced or one of the lists runs out of values; in the latter case,
any returns #f
. The application of pred
to the last element of the
lists is a tail call.
Like every
, any’s name does not end with a question mark — this is
to indicate that it does not return a simple boolean (
#t` or #f
), but
a general value.
(any integer? '(a 3 b 2.7)) => #t
(any integer? '(a 3.1 b 2.7)) => #f
(any < '(3 1 4 1 5)
'(2 7 1 8 2)) => #t
R5RS procedure
Proc
must be a procedure of one argument. The procedure
call-with-current-continuation
packages up the current continuation
(see the rationale below) as an "escape procedure" and passes it as
an argument to proc
. The escape procedure is a Scheme procedure that, if
it is later called, will abandon whatever continuation is in effect at
that later time and will instead use the continuation that was in effect
when the escape procedure was created. Calling the escape procedure may cause
the invocation of before and after thunks installed using dynamic-wind
.
The escape procedure accepts the same number of arguments as
the continuation to the original call to
call-with-current-continuation
. Except for continuations created
by the call-with-values
procedure, all continuations take exactly
one value.
The escape procedure that is passed to proc has unlimited extent just like any other procedure in Scheme. It may be stored in variables or data structures and may be called as many times as desired.
The following examples show only the most common ways in which
call-with-current-continuation
is used. If all real uses were as simple
as these examples, there would be no need for a procedure with the power
of call-with-current-continuation
.
(call-with-current-continuation
(lambda (exit)
(for-each (lambda (x)
(if (negative? x)
(exit x)))
'(54 0 37 -3 245 19))
#t)) => -3
(define list-length
(lambda (obj)
(call-with-current-continuation
(lambda (return)
(letrec ((r
(lambda (obj)
(cond ((null? obj) 0)
((pair? obj)
(+ (r (cdr obj)) 1))
(else (return #f))))))
(r obj))))))
(list-length '(1 2 3 4)) => 4
(list-length '(a b . c)) => #f
common use of call-with-current-continuation
is for structured, non-local exits from loops or procedure bodies,
but in fact call-with-current-continuation is extremely useful
for implementing a wide variety of advanced control structures.
|
Whenever a Scheme expression is evaluated there is a continuation
wanting the result of the expression. The continuation represents
an entire (default) future for the computation. If the expression
is evaluated at top level, for example, then the continuation
might take the result, print it on the screen, prompt for the
next input, evaluate it, and so on forever. Most of the time the
continuation includes actions specified by user code, as in a
continuation that will take the result, multiply it by the value
stored in a local variable, add seven, and give the answer to the
top level continuation to be printed. Normally these ubiquitous
continuations are hidden behind the scenes and programmers do not
think much about them. On rare occasions, however, a programmer
may need to deal with continuations explicitly.
Call-with-current-continuation
allows Scheme
programmers to do that by creating a procedure that acts just
like the current continuation.
call/cc is just another name for
call-with-current-continuation .
|
STklos procedure
call/ec
is an short name for call-with-escape-continuation
. call/ec
calls proc
with one parameter, which is the current escape continuation
(a continuation which can only be used to abort a computation and hence
cannot be "re-enterered").
(list 1
(call/ec (lambda (return) (list 'a (return 'b) 'c)))
3) => (1 b 3)
call/ec
is cheaper than the full call/cc
. It is particularily useful
when all the power of call/cc
is not needded.
R5RS procedure
Delivers all of its arguments to its continuation.
R5RS imposes to use multiple values in the context
of a call-with-values . In STklos, if values is not used with
call-with-values , only the first value is used (i.e. others values are
ignored)).
|
R5RS procedure
Calls its producer argument with no values and a continuation that, when passed some values, calls the consumer procedure with those values as arguments. The continuation for the call to consumer is the continuation of the call to call-with-values.
(call-with-values (lambda () (values 4 5))
(lambda (a b) b)) => 5
(call-with-values * -) => -1
STklos syntax
This form is defined in SRFI-8 (Receive: Binding to multiple values). It simplifies
the usage of multiple values. Specifically, <formals>
can have any
of three forms:
-
(
<variable1>
…<variablen>
): The environment in which the receive-expression is evaluated is extended by binding<variable1>
, …,<variablen>
to fresh locations.
The<expression>
is evaluated, and its values are stored into those locations. (It is an error if<expression>
does not have exactly n values.) -
<variable>
: The environment in which the receive-expression is evaluated is extended by binding<variable>
to a fresh location.
The<expression>
is evaluated, its values are converted into a newly allocated list, and the list is stored in the location bound to<variable>
. -
(
<variable1>
…<variablen>
.<variablen+1>
): The environment in which the receive-expression is evaluated is extended by binding<variable1>
, …,<variablen+1>
to fresh locations. The<expression>
is evaluated. Its first n values are stored into the locations bound to<variable1>
…<variablen>
. Any remaining values are converted into a newly allocated list, which is stored into the location bound to<variablen+1>
. (It is an error if<expression>
does not have at least n values.
In any case, the expressions in <body>
are evaluated sequentially in
the extended environment. The results of the last expression in the body
are the values of the receive-expression.
(let ((n 123))
(receive (q r)
(values (quotient n 10) (modulo n 10))
(cons q r)))
=> (12 . 3)
R5RS procedure
Calls thunk
without arguments, returning the result(s) of this call.
Before
and after
are called, also without arguments, as required by
the following rules (note that in the absence of calls to continuations
captured using call-with-current-continuation
the three arguments are
called once each, in order). Before
is called whenever execution enters
the dynamic extent of the call to thunk
and after
is called whenever
it exits that dynamic extent. The dynamic extent of a procedure call is
the period between when the call is initiated and when it returns.
In Scheme, because of call-with-current-continuation
, the dynamic
extent of a call may not be a single, connected time period. It is
defined as follows:
-
The dynamic extent is entered when execution of the body of the called procedure begins.
-
The dynamic extent is also entered when execution is not within the dynamic extent and a continuation is invoked that was captured (using
call-with-current-continuation
) during the dynamic extent. -
It is exited when the called procedure returns.
-
It is also exited when execution is within the dynamic extent and a continuation is invoked that was captured while not within the dynamic extent.
If a second call to dynamic-wind
occurs within the dynamic extent
of the call to thunk
and then a continuation is invoked in such a
way that the afters from these two invocations of dynamic-wind
are both to be called, then the after associated with the
second (inner) call to dynamic-wind
is called first.
If a second call to dynamic-wind
occurs within the dynamic extent
of the call to thunk
and then a continuation is invoked in such a
way that the befores from these two invocations of dynamic-wind
are both to be called, then the before associated with the
first (outer) call to dynamic-wind
is called first.
If invoking a continuation requires calling the before
from one
call to dynamic-wind
and the after
from another, then the after
is called first.
The effect of using a captured continuation to enter or exit the
dynamic extent of a call to before
or after
is undefined.
(let ((path '())
(c #f))
(let ((add (lambda (s)
(set! path (cons s path)))))
(dynamic-wind
(lambda () (add 'connect))
(lambda ()
(add (call-with-current-continuation
(lambda (c0)
(set! c c0)
'talk1))))
(lambda () (add 'disconnect)))
(if (< (length path) 4)
(c 'talk2)
(reverse path))))
=> (connect talk1 disconnect
connect talk2 disconnect)
R5RS procedure
Evaluates expression in the specified environment and returns its
value. Expression
must be a valid Scheme expression represented
as data. Environment
may be a R5RS environment-specifier
(interaction-environment
, scheme-report-environment
or
null-environment
) or a STklos module.
(eval '(* 7 3) (scheme-report-environment 5))
=> 21
(let ((f (eval '(lambda (f x) (f x x))
(null-environment 5))))
(f + 10))
=> 20
(define-module A
(define x 1))
(eval '(cons x x) (find-module 'A))
=> (1 . 1)
R7RS procedure
This procedure returns a specifier for the environment that results by starting with an empty environment and then importing each set, considered as an import set, into it. The bindings of the environment represented by the specifier, as is the environment itself.
In STklos,
- each set
argument can be a list (specifying an R7RS
library) or a symbol (specifying a module).
- the return environment is an R7RS library (which can be
passed to eval
).
(eval '(* 7 3) (environment '(scheme base))) => 21
(let ((f (eval '(lambda (f x) (f x x))
(null-environment 5))))
(f + 10)) => 20
(eval '(define foo 32)
(environment '(scheme base))) => errror
(let ((e (environment '(only (scheme base) + -)
'(only (scheme write) display))))
(length (module-symbols e))) => 3
(let ((e (environment '(prefix (only (scheme base) car)
foo-))))
(module-symbols e)) => (foo-car)
R5RS procedure
Returns a specifier for an environment that contains the bindings defined in the R5RS report.
In STklos, scheme-report-environment function can be called
without the version number (defaults to 5).
|
R5RS procedure
Returns a specifier for an environment that is empty except for the (syntactic) bindings for all syntactic keywords defined in the R5RS report.
In STklos, null-environment function can be called
without the version number (defaults to 5).
|
R5RS procedure
This procedure returns the environment in the expression are evaluated by default (the STklos module). The returned environment is mutable.
STklos procedure
Read an expression from str
and evaluates it with eval
. If a module
is passed, the evaluation takes place in the environment of this module.
Otherwise, the evaluation takes place in the environment returned by
current-module
.
(define x 10)
(define-module M
(define x 100))
(eval-from-string "(+ x x)") => 20
(eval-from-string "(+ x x)" (find-module 'M)) => 200
4.12. Input and Output
R5RS states that ports represent input and output devices. However, it defines only ports which are attached to files. In STklos, ports can also be attached to strings, to a external command input or output, or even be virtual (i.e. the behavior of the port is given by the user).
-
String ports are similar to file ports, except that characters are read from (or written to) a string rather than a file.
-
External command input or output ports are implemented with Unix pipes and are called pipe ports. A pipe port is created by specifying the command to execute prefixed with the string
"| "
(that is a pipe bar followed by a space). Specification of a pipe port can occur everywhere a file name is needed. -
Virtual ports are created by supplying basic I/O functions at port creation time. These functions will be used to simulate low level accesses to a ``virtual device''. This kind of port is particularly convenient for reading or writing in a graphical window as if it was a file. Once a virtual port is created, it can be accessed as a normal port with the standard Scheme primitives.
4.12.1. Ports
R7RS procedure
The call-with-port
procedure calls proc
with port
as an
argument. If proc
returns, then the port
is closed automatically
and the values yielded by the proc
are returned.
If proc
does not return, then the port
must not be closed
automatically unless it is possible to prove that the port
will never again be used for a read or write operation.
It is an error if proc does not accept one argument.
R5RS procedure
String
should be a string naming a file, and proc
should be a procedure
that accepts one argument. For call-with-input-file
, the file should
already exist. These procedures call proc
with one argument: the port
obtained by opening the named file for input or output. If the file cannot
be opened, an error is signaled. If proc
returns, then the port is closed
automatically and the value(s) yielded by the proc is(are) returned.
If proc does not return, then the port will not be closed automatically.
Because Scheme’s escape procedures have unlimited extent,
it is possible to escape from the current continuation but later to escape
back in. If implementations were permitted to close the port on any escape
from the current continuation, then it would be impossible to write portable
code using both call-with-current-continuation and call-with-input-file
or call-with-output-file .
|
STklos procedure
behaves as call-with-input-file
except that the port passed to proc
is the sting port obtained from port
.
(call-with-input-string "123 456"
(lambda (x)
(let* ((n1 (read x))
(n2 (read x)))
(cons n1 n2)))) => (123 . 456)
STklos procedure
Proc
should be a procedure of one argument. Call-with-output-string
calls proc
with a freshly opened output string port. The result of
this procedure is a string containing all the text that has been written
on the string port.
(call-with-output-string
(lambda (x) (write 123 x) (display "Hello" x))) => "123Hello"
R5RS procedure
Returns #t
if obj
is an input port or output port respectively,
otherwise returns #f
.
R7RS procedure
Returns #t
if obj
is a textual port or binary port respectively,
otherwise returns #f
.
R7RS procedure
Returns #t
if obj
is an input port or an output port,
otherwise returns #f
.
STklos procedure
Returns #t
if obj
is an input string port or output string port
respectively, otherwise returns #f
.
STklos procedure
Returns #t
if obj
is an input bytevector port or output bytevector port
respectively, otherwise returns #f
.
STklos procedure
Returns #t
if obj
is a file input port or a file output port respectively,
otherwise returns #f
.
R7RS procedure
Returns #t
if port is still open and capable of performing
input or output, respectively, and #f
otherwise.
STklos procedure
Returns #t
if obj
is a virtual input port or a virtual output port
respectively, otherwise returns #f
.
STklos procedure
Returns #t
if port
is connected to a terminal and #f
otherwise.
R5RS procedure
Returns the current default input or output port.
STklos procedure
Returns the current default error port.
R5RS procedure
String
should be a string naming a file, and proc
should be a
procedure of no arguments. For with-input-from-file
, the file should
already exist. The file is opened for input or output, an input or output
port connected to it is made the default value returned by
current-input-port
or current-output-port
(and is used by (read)
,
(write obj)
, and so forth), and the thunk is called with no arguments.
When the thunk returns, the port is closed and the previous default is
restored. With-input-from-file
and with-output-to-file
return(s)
the value(s) yielded by thunk.
The following example uses a pipe port opened for reading. It permits to read all the lines produced by an external ,(emph "ls") command (i.e. the output of the ,(emph "ls") command is ,(emph "redirected") to the Scheme pipe port).
(with-input-from-file "| ls -ls"
(lambda ()
(do ((l (read-line) (read-line)))
((eof-object? l))
(display l)
(newline))))
Hereafter is another example of Unix command redirection. This time, it is the standard input of the Unix command which is redirected.
(with-output-to-file "| mail root"
(lambda ()
(display "A simple mail from Scheme")
(newline)))
STklos procedure
This procedure is similar to with-output-to-file, excepted that it uses the current error port instead of the output port.
STklos procedure
A string port is opened for input from string
. Current-input-port
is set to the port and thunk
is called. When thunk
returns,
the previous default input port is restored. With-input-from-string
returns the value(s) computed by thunk
.
(with-input-from-string "123 456"
(lambda () (read))) => 123
STklos procedure
A string port is opened for output. Current-output-port
is set to it and thunk
is called. When thunk
returns,
the previous default output port is restored. With-output-to-string
returns the string containing the text written on the string port.
(with-output-to-string
(lambda () (write 123) (write "Hello"))) => "123\"Hello\""
STklos procedure
Port
should be a port, and proc
should be a
procedure of no arguments. These procedures do a job similar to the
with-…-file
counterparts excepted that they use an open port instead
of string specifying a file name
R5RS procedure
Takes a string naming an existing file and returns an input port capable of delivering characters from the file. If the file cannot be opened, an error is signalled.
if filename starts with the string "| " , this procedure returns a pipe port.
Consequently, it is not possible to open a file whose name starts with those two
characters.
|
STklos procedure
Returns an input string port capable of delivering characters from
str
.
R7RS procedure
Takes a bytevector and returns a binary input port that
delivers bytes from the bytevector
.
STklos procedure
Returns a virtual port using the read-char
procedure to read a
character from the port, ready?
to know if there is any data to
read from the port, eof?
to know if the end of file is reached
on the port and finally close
to close the port. All these
procedure takes one parameter which is the port from which the input
takes place. Open-input-virtual
accepts also the special value
#f
for the I/O procedures with the following conventions:
-
if
read-char
oreof?
is#f
, any attempt to read the virtual port will return an eof object; -
if
ready?
is#f
, the file is always ready for reading; -
if
close
is#f
, no action is done when the port is closed.
Hereafter is a possible implementation of open-input-string
using virtual ports:
(define (open-input-string str)
(let ((index 0))
(open-input-virtual
:read-char (lambda (p)
;; test on eof is already done by the system
(let ((res (string-ref str index)))
(set! index (+ index 1))
res))
:eof? (lambda (p) (>= index (string-length str))))))
R5RS procedure
Takes a string naming an output file to be created and returns an output port capable of writing characters to a new file by that name. If the file cannot be opened, an error is signalled. If a file with the given name already exists, it is rewritten.
if filename starts with the string "| " , this procedure returns a pipe port.
Consequently, it is not possible to open a file whose name starts with those two
characters.
|
STklos procedure
Returns an output string port capable of receiving and collecting characters.
R7RS procedure
Returns a binary output port that will accumulate bytes
for retrieval by get-output-bytevector
.
STklos procedure
Returns a virtual port using the write-char
procedure to write a
character to the port, write-string
to write a string to the port,
flush
to (eventuelly) flush the characters on the port and finally
close`to close the port. `Write-char
takes two parameters: a character and
the port to which the output must be done. write-string
takes two
parameters: a string and a port. Flush
and Close
take one
parameter which is the port on which the action must be done.
Open-output-virtual
accepts also the special value #f
for the I/O procedures. If a procedure is #f
nothing is done
on the corresponding action.
Hereafter is a (very inefficient) implementation of a variant of
open-output-string
using virtual ports. The value of the output
string is printed when the port is closed:
(define (open-output-string)
(let ((str ""))
(open-output-virtual
:write-char (lambda (c p)
(set! str (string-append str (string c))))
:write-string (lambda (s p)
(set! str (string-append str s)))
:close (lambda (p) (write str) (newline)))))
write-string is mainly used for writing strings and is
generally more efficient than writing the string character by character.
However, if write-string is not provided, strings are printed with
write-char . On the other hand, if write-char is absent,
characters are written by successive allocation of one character strings.
|
Hereafter is another example: a virtual file port where all characters are converted to upper case:
(define (open-output-uppercase-file file)
(let ((out (open-file file "w")))
(and out
(open-output-virtual
:write-string (lambda (s p)
(display (string-upper s) out))
:close (lambda (p)
(close-port out))))))
STklos procedure
Opens the file whose name is filename
with the specified string
mode
which can be:
-
"r"
to open the file for reading. The stream is positioned at the beginning of the file. -
"r+"
to open the file for reading and writing. The stream is positioned at the beginning of the file. -
"w"
to truncate the file to zero length or create the file for writing. The stream is positioned at the beginning of the file. -
"w+"
to open the file for reading and writing. The file is created if it does not exist, otherwise it is truncated. The stream is positioned at the beginning of the file. -
"a"
to open the file for writing. The file is created if it does not exist. The stream is positioned at the end of the file. -
"a+"
to open the file for reading and writing. The file is created if it does not exist. The stream is positioned at the end of the file.
If the file can be opened, open-file
returns the textual port associated
with the given file, otherwise it returns #f
. Here again, the magic
string "| " permits to open a pipe port. (In this case mode can only be
"r"
or "w"
.)
STklos procedure
Returns a string containing all the text that has been written on the
output string port
.
(let ((p (open-output-string)))
(display "Hello, world" p)
(get-output-string p)) => "Hello, world"
STklos procedure
Returns a bytevector consisting of the bytes that have been
output to the port
so far in the order they were output.
(let ((p (open-output-bytevector)))
(u8-write 65)
(u8-write 66)
(get-output-bytevector p)) => #u8(65 66)
R5RS procedure
Closes the port associated with port
, rendering the port incapable of
delivering or accepting characters. These routines have no effect if the
port has already been closed. The value returned is void.
R7RS procedure
Closes the port associated with port
.
STklos procedure
Sets the port position to the beginning of port
. The value returned by
port-rewind
is void.
STklos procedure
Sets the file position for the given port
to the position pos
.
The new position, measured in bytes, is obtained by adding pos
bytes to the position specified by whence
. If passed, whence
must be one of :start
, :current
or :end
. The resulting
position is relative to the start of the file, the current position
indicator, or end-of-file, respectively. If whence
is omitted, it
defaults to :start
.
After using port-seek, the value returned by
port-current-line may be incorrect.
|
STklos procedure
Returns the current line number associated to the given input port
as an
integer. The port
argument may be omitted, in which case it defaults to
the value returned by current-input-port
.
The port-seek , read-chars and read-chars! procedures
generally break the line-number. After using one of these procedures, the
value returned by port-current-line will be -1 (except a port-seek
at the beginning of the port reinitializes the line counter).
|
STklos procedure
Returns the position associated to the given port
as an
integer (i.e. number of characters from the beginning of the port).
The port
argument may be omitted, in which case it defaults to
the value returned by current-input-port
.
STklos procedure
Returns the file name used to open port
; port
must be a file port.
STklos procedure
port-idle-register!
allows to register thunk
as an idle handler
when reading on port. That means that thunk
will be called continuously
while waiting an input on port
(and only while using a reading
primitive on this port). port-idle-unregister!
can be used to
unregister a handler previously set by port-idle-register!
. The
primitive port-idle-reset!
unregisters all the handlers set on
port
.
Hereafter is a (not too realistic) example: a message will be displayed repeatedly until a sexpr is read on the current input port.
(let ((idle (lambda () (display "Nothing to read!\n"))))
(port-idle-register! (current-input-port) idle)
(let ((result (read)))
(port-idle-unregister! (current-input-port) idle)
result))
STklos procedure
port-closed?
returns #t
if port
is closed and #f
otherwise.
On the contrary, port-open?
returns #t
if port
is open and
#f
otherwise.
port-closed? was the usual STklos function to
test if a port is closed. port-open? has been added to be the companion
of the R7RS functions input-port-open? and output-port-open?
|
STklos procedure
Associate the procedure thunk
to port
. The thunk will be called
the first time port
is closed.
(let* ((tmp (temporary-file-name))
(p (open-output-file tmp))
(foo #t))
(port-close-hook-set! p
(lambda()
(remove-file tmp)
(set! foo #t)))
(close-port p)
foo)
STklos procedure
Returns the user close procedure associated to the given port
.
The following procedures are defined in *link:http://srfi.schemers.org/srfi-192/srfi-192.html[SRFI-192]* (_Port Positioning_)(((SRFI-192))) which is fully supported:((("SRFI-192"))) (((port-has-port-position?)))
STklos procedure
The port-has-port-position? procedure returns #t
if the port
supports the port-position operation, and #f
otherwise. If the port
does not support the operation, port-position signals an error.
STklos procedure
The port-position procedure returns an object representing the information state about the port current position as is necessary to save and restore that position. This value can be useful only as the pos argument to set-port-position!, if the latter is even supported on the port. However, if the port is binary and the object is an exact integer, then it is the position measured in bytes, and can be used to compute a new position some specified number of bytes away.
STklos procedure
The port-has-set-port-position!? procedure returns #t
if the port supports
the set-port-position! operation, and #f
otherwise.
STklos procedure
For a textual port, it is implementation-defined what happens if pos is not the return value of a call to port-position on port. However, a binary port will also accept an exact integer, in which case the port position is set to the specified number of bytes from the beginning of the port data. If this is not sufficient information to specify the port state, or the specified position is uninterpretable by the port, an error satisfying i/o-invalid-position-error? is signaled.
If set-port-position!
procedure is invoked on a port that does not support
the operation or if pos is not in the range of valid positions of port,
set-port-position!
signals an error. Otherwise, it sets the current position
of the port to pos. If port is an output port, set-port-position!
first flushes
port (even if the port position will not change).
If port is a binary output port and the current position is set beyond the
current end of the data in the underlying data sink, the object is not extended
until new data is written at that position. The contents of any intervening
positions are unspecified. It is also possible to set the position of a binary
input port beyond the end of the data in the data source, but a read will fail
unless the data has been extended by other means. File ports can always be
extended in this manner within the limits of the underlying operating system.
In other types of ports, if an attempt is made to set the position beyond the
current end of data in the underlying object, and the object does not support
extension, an error satisfying i/o-invalid-position-error?
is signaled.
STklos procedure
Returns a condition object which satisfies i/o-invalid-position-error?. The pos argument represents a position passed to set-position!.
STklos procedure
Returns #t
if obj
is an object created by
make-i/o-invalid-position-error?
or an object raised in the circumstances
described in SRFI-192 (attempt to access an invalid position in the
stream), or #f
if it is not.
4.12.2. Input
R5RS procedure
Read
converts external representations of Scheme objects into the
objects themselves. Read
returns the next object parsable from the given
input port, updating port to point to the first character past the end of
the external representation of the object.
If an end of file is encountered in the input before any characters are found that can begin an object, then an end of file object is returned. The port remains open, and further attempts to read will also return an end of file object. If an end of file is encountered after the beginning of an object’s external representation, but the external representation is incomplete and therefore not parsable, an error is signalled.
The port argument may be omitted, in which case it defaults to the value
returned by current-input-port
. It is an error to read from a closed port.
STklos read
supports the SRFI-10 #,()
form that can be used
to denote values that do not have a convenient printed representation. See
the SRFI document for more information.
STklos procedure
read-with-shared-structure
is identical to read
. It has been added to
be compatible with ,(link-srfi 38). STklos always knew how to deal with
recursive input data. read/ss
is only a shorter name for
read-with-shared-structure
.
STklos procedure
This procedure permits to define a new user to reader constructor procedure at run-time. It is defined in ,(link-srfi 10) document. See SRFI document for more information.
(define-reader-ctor 'rev (lambda (x y) (cons y x)))
(with-input-from-string "#,(rev 1 2)" read)
=> (2 . 1)
R5RS procedure
Returns the next character available from the input port
, updating the port
to point to the following character. If no more characters are available,
an end of file object is returned. Port
may be omitted, in which case
it defaults to the value returned by current-input-port
.
STklos procedure
Returns a newly allocated string made of size
characters read from port
.
If less than size
characters are available on the input port, the returned
string is smaller than size
and its size is the number of available
characters. Port
may be omitted, in which case it defaults to the
value returned by current-input-port
.
This function was previously called read-chars . Usage
of the old name is deprecated.
|
R7RS procedure
Reads the next k
bytes, or as many as are available
before the end of file, from the textual input port
into a
newly allocated string in left-to-right order and returns the
string. If no characters are available before the end of file,
an end-of-file object is returned.
R7RS procedure
Reads the next end - start
bytes, or as many as are available
before the end of file, from the binary input port
into bytevector
in left-to-right order beginning at the start
position. If end
is not supplied, reads until the end of
bytevector
has been reached. If start
is not supplied, reads
beginning at position 0. Returns the number of bytes read.
If no bytes are available, an end-of-file object is returned.
STklos procedure
This function reads the characters available from port
in the string str
by chuncks whose size is equal to the length of str
.
The value returned by read-bytes!
is an integer indicating the number
of characters read. Port
may be omitted, in which case it defaults to the
value returned by current-input-port
.
This function is similar to read-bytes
except that it avoids to allocate
a new string for each read.
(define (copy-file from to)
(let* ((size 1024)
(in (open-input-file from))
(out (open-output-file to))
(s (make-string size)))
(let Loop ()
(let ((n (read-bytes! s in)))
(cond
((= n size)
(write-chars s out)
(Loop))
(else
(write-chars (substring s 0 n) out)
(close-port out)))))))
This function was previously called read-chars! . Usage
of the old name is deprecated.
|
STklos procedure
Returns the next character available from the input port
as an integer.
If the end of file is reached, this function returns the end of file
object.
R5RS procedure
Returns the next character available from the input port
, without updating
the port to point to the following character. If no more characters are
available, an end of file object is returned. Port
may be omitted, in
which case it defaults to the value returned by current-input-port
.
The value returned by a call to peek-char is the same as the
value that would have been returned by a call to read-char with the same
port. The only difference is that the very next call to read-char or
peek-char on that port will return the value returned by the preceding
call to peek-char . In particular, a call to peek-char on an interactive
port will hang waiting for input whenever a call to read-char would have
hung.
|
STklos procedure
Returns the next character available from the input port
, without updating
the port to point to the following character. Whereas peek-char
returns a character, this function returns an integer between 0and 255.
R5RS procedure
Returns #t
if obj
is an end of file object, otherwise returns #f
.
STklos procedure
end of file
Returns an end of file object. Note that the special notation #eof
is
another way to return such an end of file object.
R5RS procedure
Returns #t
if a character is ready on the input port and returns #f
otherwise. If char-ready returns #t
then the next read-char operation on
the given port is guaranteed not to hang. If the port is at end of file
then char-ready?
returns #t
. Port may be omitted, in which case it
defaults to the value returned by current-input-port
.
R7RS procedure
Reads the next k
characters, or as many as are available
before the end of file, from the textual input port
into a
newly allocated string in left-to-right order and returns the
string. If no characters are available before the end of file,
an end-of-file object is returned.
R7RS procedure
Returns the next byte available from the binary input port
,
updating the port
to point to the following byte. If no more
bytes are available, an end-of-file object is returned.
This function is similar to the read-byte
function, excepted that it can be used only on a binary port.
|
R7RS procedure
Returns the next byte available from the binary input port
,
but without updating the port
to point to the following
byte. If no more bytes are available, an end-of-file object
is returned.
This function is similar to the peek-byte
function, excepted that it can be used only on a binary port.
|
R7RS procedure
Returns #t
if a byte is ready on the binary input port
and
returns #f
otherwise. If u8-ready?
returns #t
then the
next read-u8 operation on the given port is guaranteed
not to hang. If the port
is at end of file then u8-ready?
returns #t
.
STklos procedure
Reads the next line available from the input port port
. This function
returns 2 values: the first one is the string which contains the line
read, and the second one is the end of line delimiter. The end of line
delimiter can be an end of file object, a character or a string in case
of a multiple character delimiter. If no more characters are available
on port
, an end of file object is returned. Port
may be omitted,
in which case it defaults to the value returned by current-input-port
.
As said in primitive values , if read-line is not
used in the context of call-with-values , the second value returned by
this procedure is ignored.
|
STklos procedure
Performs a read from the given str
. If str
is the empty string,
an end of file object is returned.
(read-from-string "123 456") => 123
(read-from-string "") => an eof object
STklos procedure
All these procedures take a port opened for reading. Port→string
reads
port
until the it reads an end of file object and returns all the
characters read as a string. Port→sexp-list
and port→string-list
do the same things except that they return a list of S-expressions and
a list of strings respectively. For the following example we suppose that
file "foo"
is formed of two lines which contains respectively the number
100
and the string "bar"
.
(port->sexp-list (open-input-file "foo")) => (100 "bar")
(port->string-list (open-input-file "foo")) => ("100" ""bar"")
4.12.3. Output
R5RS procedure
Writes a written representation of obj
to the given port
. Strings that
appear in the written representation are enclosed in doublequotes, and
within those strings backslash and doublequote characters are escaped
by backslashes. Character objects are written using the ,(emph "#\") notation.
Write
returns an unspecified value. The port
argument may be omitted, in
which case it defaults to the value returned by current-output-port
.
R7RS procedure
Writes a written representation of obj
to the given port. The
main difference with the write
procedure is that write*
handles data structures with cycles. Circular structure written by
this procedure use the "#n="
)) and "#n#"
))
notations (see Section 1.2.4).
This function is also called write* .
The name write* was the name used by STklos for
write-shared before it was introduced in R7RS.
|
STklos procedure
write-with-shared-structure
has been added to be compatible with
SRFI-38 (External representation of shared structures). It is is identical to write*
, except that it accepts one
more parameter (optarg
). This parameter, which is not specified
in SRFI-38, is always ignored. write/ss
is only a shorter name for
write-with-shared-structure
.
R5RS procedure
Writes a representation of obj
to the given port
. Strings that
appear in the written representation are not enclosed in
doublequotes, and no characters are escaped within those
strings. Character objects appear in the representation as if
written by write-char
instead of by write
. Display
returns an
unspecified value. The port
argument may be omitted, in which
case it defaults to the value returned by current-output-port
.
Write is intended for producing machine-readable
output and display is for producing human-readable output.
|
As required by R7RS does not loop forever when
obj contains self-references.
|
STklos procedure
The display-shared
procedure is the same as display
, except
that shared structure are represented using datum labels.
STklos procedure
The display-simple
procedure is the same as display
, except
that shared structure is never represented using datum labels.
This can cause display-simple
not to terminate if obj
contains circular structure.
R5RS procedure
Writes an end of line to port
. Exactly how this is done differs from
one operating system to another. Returns an unspecified value. The port
argument may be omitted, in which case it defaults to the value returned
by current-output-port
.
R7RS procedure
Writes the characters of string
from start
to end
in
left-to-right order to the textual output port
.
R7RS procedure
Writes the byte
to the given binary output port.
R7RS procedure
Writes the bytes of bytevector
from start
to end
in
left-to-right order to the binary output port
.
R5RS procedure
Writes the character char
(not an external representation of the
character) to the given port
and returns an unspecified value.
The port
argument may be omitted, in which case it defaults to the
value returned by current-output-port
.
STklos procedure
Writes the characters of string str
to the given port
and
returns an unspecified value. The port
argument may be omitted,
in which case it defaults to the value returned by
current-output-port
.
This function is generally
faster than display for strings. Furthermore, this primitive does
not use the buffer associated to port .
|
STklos procedure
Write byte b
to the port. b
must be an exact integer in range between 0
and 255.
STklos procedure
Writes the obj`s to the given `port
, according to the format
string str
. Str
is written literally, except for the following
sequences:
-
~a
or~A
is replaced by the printed representation of the nextobj
. -
~s
or~S
is replaced by the slashified printed representation of the nextobj
. -
~w
or~W
is replaced by the printed representation of the nextobj
(circular structures are correctly handled and printed usingwrite*
). -
~d
or~D
is replaced by the decimal printed representation of the nextobj
(which must be a number). -
~x
or~X
is replaced by the hexadecimal printed representation of the nextobj
(which must be a number). -
~o
or~O
is replaced by the octal printed representation of the nextobj
(which must be a number). -
~b
or~B
is replaced by the binary printed representation of the nextobj
(which must be a number). -
~c
or~C
is replaced by the printed representation of the nextobj
(which must be a character). -
~y
or~Y
is replaced by the pretty-printed representation of the nextobj
. The standard pretty-printer is used here. -
~?
is replaced by the result of the recursive call offormat
with the two nextobj
: the first item should be a string, and the second, a list with the arguments. -
~k
or~K
is another name for~?
-
~[w[,d]]f
or~[w[,d]]F
is replaced by the printed representation of nextobj
(which must be a number) with widthw
andd
digits after the decimal. Eventually,d
may be omitted. -
~~
is replaced by a single tilde character. -
~%
is replaced by a newline -
~t
or~T
is replaced by a tabulation character. -
~&
is replaced by a newline character if it is known that the previous character was not a newline -
~_
is replaced by a space -
~h
or~H
provides some help
Port
can be a boolean or a port. If port
is #t
, output goes to
the current output port; if port
is #f
, the output is returned as a
string. Otherwise, the output is printed on the specified port.
(format #f "A test.") => "A test."
(format #f "A ~a." "test") => "A test."
(format #f "A ~s." "test") => "A "test"."
(format "~8,2F" 1/3) => " 0.33"
(format "~6F" 32) => " 32"
(format "~1,2F" 4321) => "4321.00"
(format "~1,2F" (sqrt -3.9)) => "0.00+1.97i"
(format "#d~d #x~x #o~o #b~b~%" 32 32 32 32)
=> "#d32 #x20 #o40 #b100000n"
(format #f "~&1~&~&2~&~&~&3~%")
=> "n1n2n3n"
(format "~a ~? ~a" 'a "~s" '(new) 'test)
=> "a new test"
The second form of format is compliant with SRFI-28 (Basic Format Strings).
That is, when port is omitted, the output is returned as a string as if
port was given the value #f .
|
Since version 0.58, format is also compliant with SRFI-48 (Intermediate Format Strings).
|
STklos procedure
Flushes the buffer associated with the given output port
. The
port
argument may be omitted, in which case it defaults to the value
returned by current-output-port
STklos procedure
These procedures display all their arguments followed by a newline. The
procedure print
uses the standard output port, whereas printerr
uses the
current error port
STklos procedure
These procedures are specialized versions of format
primitive.
In these procedures, fmt
is a string using the format
conventions.
printf
outputs go on the current output port.
fprintf
outputs go on the specified port
.
eprintf
outputs go on the current error port (note that eprintf always
flushes the characters printed).
4.13. System interface
The STklos system interface offers all the functions defined in R7RS. Note, that the base implementation provides also a subset of the functions defined in SRFI-170 (POSIX API). These functions are described here.
Note, however that SRFI-170 is fully supported and accessing the other functions it defines can be done by requiring it, as the other SRFIs that STklos supports.
4.13.1. Loading code
R5RS procedure
Filename
should be a string naming an existing file containing Scheme
expressions. Load
has been extended in STklos to allow loading of
files containing Scheme compiled code as well as object files (aka
shared objects). The loading of object files is not available on
all architectures. The value returned by load
is void.
If the file whose name is filename
cannot be located, load
will try
to find it in one of the directories given by "load-path"
with the suffixes given by "load-suffixes"
.
STklos procedure
try-load
tries to load the file named filename
. As with load
,
try-load
tries to find the file given the current load path
and a set of suffixes if filename
cannot be loaded. If try-load
is able to find a readable file, it is loaded, and try-load
returns
#t
. Otherwise, try-load
retuns #f
.
STklos procedure
In its first form, find-path
returns the path name of the file
that should be loaded by the procedure load
given the name str
.
The string returned depends of the current load path and of the
currently accepted suffixes.
The other forms of find-path
are more general and allow to give a path
list (a list of strings representing supposed directories) and a set
of suffixes (given as a list of strings too) to try for finding a file.
If no file is found, find-path
returns #f
.
For instance, on a "classical" Unix box:
(find-path "passwd" '("/bin" "/etc" "/tmp"))
=> "/etc/passwd"
(find-path "stdio" '("/usr" "/usr/include") '("c" "h" "stk"))
=> "/usr/include/stdio.h"
STklos procedure
Returns the path of the file that is currently being load.
STklos procedure
Require
loads the file whose name is string
if it was not
previously "provided". Provide
permits to store string
in
the list of already provided files. Providing a file permits to avoid
subsequent loads of this file. Require/provide
is more or less equivalent to
a require
followed by a provide
. Provided?
returns #t
if
string
was already provided; it returns #f
otherwise.
4.13.2. File Primitives
STklos procedure
This parameter object permits to change the default prefix used to build
temporary file name. Its default value is built using the TMPDIR
environment variable (if it is defined) and the current process ID.
If a value is provided, it must be a string designating a valid prefix path.
This parameter object is also defined in SRFI-170 (POSIX API).
STklos procedure
Creates a new temporary file and returns two values: its name and an opened
file port on it. The optional argument specifies the filename prefix
to use, and defaults to the result of invoking temp-file-prefix
.
The returned file port is opened in read/write mode. It ensures that
the name cannot be reused by another process before being used
in the program that calls create-temp-file
.
Note, that if the opened port is not used, it can be closed and collected
by the GC.
(let-values (((name port) (create-temp-file)))
(let ((msg (format "Name: ~sn" name)))
(display msg)
(display msg port)
(close-port port))) => prints the name of the temp. file on the
current output port and in the file itself.
This function is also defined in SRFI-170 (POSIX API).However,
in SRFI-170, create-temp-file returns only the name of the temporary file.
|
temporary-file-name is another name for this function.
|
STklos procedure
Creates a new temporary directory and returns its name as a string.
The optional argument specifies the filename prefix to use, and
defaults to the result of invoking temp-file-prefix
.
STklos procedure
Renames the file whose path-name is string1
to a file whose path-name is
string2
. The result of rename-file
is void.
This function is also defined in SRFI-170 (POSIX API).
R7RS procedure
Removes the file whose path name is given in string
.
The result of delete-file
is void.
This function is also called remove-file
for compatibility
reasons. ,(index "remove-file")
STklos procedure
Copies the file whose path-name is string1
to a file whose path-name is
string2
. If the file string2
already exists, its content prior
the call to copy-file
is lost. The result of copy-file
is void.
STklos procedure
Copy the content of port in
, which must be opened for reading, on
port out
, which must be opened for writing. If max
is not specified,
All the characters from the input port are copied on ouput port. If max
is specified, it must be an integer indicating the maximum number of characters
which are copied from in
to out
.
R7RS procedure
Returns #t
if the path name given in string
denotes an existing file;
returns #f
otherwise.
STklos procedure
Returns #t
if the predicate is true for the path name given in
string
; returns #f
otherwise (or if string
denotes a file
which does not exist).
STklos procedure
Returns the size of the file whose path name is given in
string
. If string
denotes a file which does not exist,
file-size
returns #f
.
STklos procedure
Returns a string containing the current working directory.
STklos procedure
Change the access mode of the file whose path name is given in string
.
The options must be composed of either an integer or one of the
following symbols read
, write
or execute
. Giving no option to chmod
is equivalent to pass it the integer 0
. If the operation succeeds,
chmod
returns #t
; otherwise it returns #f
.
(chmod "~/.config/stklos/stklosrc" 'read 'execute)
(chmod "~/.config/stklos/stklosrc" #o644)
STklos procedure
Changes the current directory to the directory given in string dir
.
STklos procedure
Create a directory with name dir
. If permissions
is omitted, it
defaults to #o775 (masked by the current umask).
This function is also defined in SRFI-170 (POSIX API). The old name
make-directory is deprecated.
|
STklos procedure
Create a directory with name dir
. No error is signaled if dir
already exists.
Parent directories of dir
are created as needed. If permissions
is omitted,
it defaults to #o775 (masked by the current umask).
This function was also called make-directories . This old name is
obsolete.
|
STklos procedure
Create a directory with name dir
(and its parent directories if needed), if it
does not exist yet.
STklos procedure
Delete the directory with name dir
.
This function is also defined in SRFI-170 (POSIX API). The name
remove-directory is kept for compatibility.
|
STklos procedure
Returns the list of the files in the directory path
. The dotfiles?
flag
(default #f
) causes files beginning with ,(q ".") to be included in the list.
Regardless of the value of dotfiles?
, the two files ,(q ".") and ,(q "..")
are never returned.
This function is also defined in SRFI-170 (POSIX API).
STklos procedure
Expand-file-name
expands the filename given in path
to
an absolute path.
;; Current directory is ~eg/stklos (i.e. /users/eg/stklos)
(expand-file-name "..") => "/users/eg"
(expand-file-name "~eg/../eg/bin") => "/users/eg/bin"
(expand-file-name "~/stklos)" => "/users/eg/stk"
STklos procedure
Expands all symbolic links in path
and returns its canonicalized
absolute path name. The resulting path does not have symbolic links.
If path
doesn’t designate a valid path name, canonical-file-name
returns #f
.
STklos procedure
Returns an `exploded'' list of the path name components given in
`string
.
The first element in the list denotes if the given string
is an
absolute path or a relative one, being "/" or "." respectively.
Each component of this list is a string.
(decompose-file-name "/a/b/c.stk") => ("/" "a" "b" "c.stk")
(decompose-file-name "a/b/c.stk") => ("." "a" "b" "c.stk")
STklos procedure
On Win32 system, when compiled with the Cygwin environment,
file names are internally represented in a POSIX-like internal form.
Winify-file-bame
permits to obtain back the Win32 name of an interned
file name
(winify-file-name "/tmp")
=> "C:\cygwin\tmp"
(list (getcwd) (winify-file-name (getcwd)))
=> ("//saxo/homes/eg/Projects/STklos"
"\\saxo\homes\eg\Projects\STklos")
STklos procedure
On Win32 system, when compiled with the Cygwin environment,
file names are internally represented in a POSIX-like internal form.
posixify-file-bame
permits to obtain the interned file name from
its external form.
file name
(posixify-file-name "C:\cygwin\tmp")
=> "/tmp"
STklos procedure
Returns a string containing the last component of the path name
given in str
.
(basename "/a/b/c.stk") => "c.stk"
STklos procedure
Returns a string containing all but the last component of the path
name given in str
.
(dirname "/a/b/c.stk") => "/a/b"
STklos procedure
Returns the suffix of given pathname
. If no suffix is found, file-suffix
returns #f
.
(file-suffix "./foo.tar.gz") => "gz"
(file-suffix "./a.b/c") => #f
(file-suffix "./a.b/c.") => ""
(file-suffix "~/.profile") => #f
STklos procedure
Returns the prefix of given pathname
.
(file-prefix "./foo.tar.gz") => "./foo.tar"
(file-prefix "./a.b/c") => "./a.b/c"
STklos procedure
Retuns the operating system file separator as a character. This is typically
#/
on Unix (or Cygwin) systems and #\
on Windows.
STklos procedure
Builds a file name from the directory dirname
and names
. For instance,
on a Unix system:
(make-path "a" "b" "c") => "a/b/c"
STklos procedure
Glob
performs file name `globbing'' in a fashion similar to the
csh shell. `Glob
returns a list of the filenames that match at least
one of pattern
arguments. The pattern
arguments may contain
the following special characters:
-
?
Matches any single character. -
*
Matches any sequence of zero or more characters. -
[chars]
Matches any single character inchars
. If chars contains a sequence of the forma-b
then any character betweena
andb
(inclusive) will match. -
x
Matches the characterx
. -
{a,b,…}
Matches any of the stringsa
,b
, etc. )
As with csh, a '.' at the beginning of a file’s name or just after
a '/' must be matched explicitly or with a @{@}
construct.
In addition, all '/' characters must be matched explicitly.
If the first character in a pattern is '~' then it refers to the home directory of the user whose name follows the '~'. If the '~' is followed immediately by '/' then the value of the environment variable HOME is used.
Glob
differs from csh globbing in two ways:
-
it does not sort its result list (use the
sort
procedure if you want the list sorted). -
glob
only returns the names of files that actually exist; in csh no check for existence is made unless a pattern contains a?
,*
, or[]
construct.
STklos procedure
This procedure returns #t
if obj
is a condition object that describes a
POSIX error, and #f
otherwise.
This function is defined in SRFI-170 (POSIX API).
STklos procedure
This procedure returns a symbol that is the name associated with the
value of errno
when the POSIX function reported an error. This can be
used to provide programmatic recovery when a POSIX function can return
more than one value of errno
.
This function is defined in SRFI-170 (POSIX API).
STklos procedure
This procedure returns a string that is an error message reflecting the value of errno when the POSIX function reported an error. This string is useful for reporting the cause of the error to the user
This function is defined in SRFI-170 (POSIX API).
STklos procedure
This procedure returns the value of errno
(an exact integer).
STklos procedure
This procedure returns the name of the Scheme procedure that raised the error.
STklos procedure
This procedure returns the list of the Scheme procedure arguments that raised the error.
4.13.3. Environment
STklos procedure
Looks for the environment variable named str
and returns its
value as a string, if it exists. Otherwise, getenv
returns #f
.
If getenv
is called without parameter, it returns the list of
all the environment variables accessible from the program as an
A-list.
(getenv "SHELL")
=> "/bin/zsh"
(getenv)
=> (("TERM" . "xterm") ("PATH" . "/bin:/usr/bin") ...)
STklos procedure
Sets the environment variable var
to value
. Var
and
value
must be strings. The result of setenv!
is void.
STklos procedure
Unsets the environment variable var
. Var
must be a string.
The result of unsetenv!
is void.
STklos defines also the R7RS (and SRFI-96) standard primivitives to acess environment variables.
R7RS procedure
Returns the value of the named environment variable as a string, or
#f
if the named environment variable is not found. The name argument
is expected to be a string. This function is similar to the getenv
. It
has been added to be support SRFI-98 (Interface to access environment variables).
R7RS procedure
Returns names and values of all the environment variables as an a-list. This function is defined by SRFI-98 (Interface to access environment variables).
STklos procedure
Builds a path as a list of strings (which is the way STklos represents
paths) from the environment variable var
, given the separator characters
given in sep
(which defaults to ":"
, the standrad Unix path separator).
If the var
is not definied in the environment,
build-path-from-shell-variable
returns the empty list.
If the shell variable MYPATH
is "/bin:/sbin:/usr/bin"`, then
(build-path-from-shell-variable "MYPATH") => ("/bin" "/sbin" "/usr/bin")
(build-path-from-shell-variable "MYPATH" "/:") => ("bin" "sbin" "usr" "bin")
4.13.4. Time
R7RS procedure
Returns an inexact number representing the current time on the International Atomic Time (TAI) scale. The value 0.0 represents midnight on January 1, 1970 TAI (equivalent to ten seconds before midnight Universal Time) and the value 1.0 represents one TAI second later.
R7RS procedure
Returns the number of jiffies as an exact integer that
have elapsed since an arbitrary, implementation-defined
epoch. A jiffy is an implementation-defined fraction of
a second which is defined by the return value of the
jiffies-per-second
procedure. The starting epoch is
guaranteed to be constant during a run of the program,
but may vary between runs.
R7RS procedure
Returns an exact integer representing the number of jiffies per second.
(define (time-length)
(let ((list (make-list 100000))
(start (current-jiffy)))
(length list)
(/ (- (current-jiffy) start)
(jiffies-per-second))))
STklos procedure
Returns an approximation of processor time, in milliseconds, used so far by the program.
STklos procedure
Suspend the execution of the program for at ms
milliseconds. Note that due
to system clock resolution, the pause may be a little bit longer. If a
signal arrives during the pause, the execution may be resumed.
STklos syntax
Evaluates the expressions expr1
, expr2
, … and returns the
result of the last expression. This form prints also the time spent
for this evaluation, in milliseconds, on the current error port.
This is CPU time, and not real ("wall") time.
4.13.5. System Information
R7RS procedure
Returns a list of the feature identifiers which cond-expand
treats as true. Here is an
example of what features
might return:
(features) => (STklos STklos-2.00 exact-complex
ieee-float full-unicode ratios little-endian ...)
STklos procedure
Returns the name of the underlying Operating System which is running
the program.
The value returned by runnin-os
is a symbol. For now, this procedure
returns either unix
, android
, windows
, or cygwin-windows
.
STklos procedure
Return the host name of the current processor as a string.
R7RS procedure
Returns the command line passed to the process as a list of strings. The first string corresponds to the command name.
STklos procedure
Returnd the name of the running program if it is a standalone and #f
otherwise. This function is defined in SRFI-193 (Command line).
STklos procedure
Returns a list of the arguments given on the shell command line. The
interpreter options are no included in the result. The name argv
is
deprecated and should not be used.
STklos procedure
Returns the number of arguments present on the command line.
STklos procedure
Returns the invocation name of the current program as a string. If the file is
not a script (in sense of SRFI-193), it is the name of the
running STklos interpreter, otherwise it is the name of the running script.
This function always returns a string whereas the command-name
procedure returns
#f
when the program name is not a script.
STklos procedure
Returns the absolute path of the current script.
If the calling program is not a script, #f
is returned.
This function is defined in SRFI-193 (Command line).
STklos procedure
Returns the non-filename part of script-file as a string.
As with script-file
, this is an absolute pathname.
STklos procedure
Returns a string identifying the current version of the system. A version is constituted of two (or three) numbers separated by a point: the version, the release numbers and, eventually, a patch number. The patch number is used for developments version only; it is absent for stable releases.
Note that implementation-version
corresponds to the SRFI-112 (Environment Inquiry) name of
this function.
STklos procedure
Returns a string identifying the current version of the system without its eventual patch number.
STklos procedure
Returns a string identifying the kind of machine which is running the
program. The result string is of the form
[os-name]-[os-version]-[cpu-architecture]
.
STklos procedure
This function is defined in SRFI-112 (Environment Inquiry); it returns the Scheme
implementation (i.e. the string "STklos"
).
STklos procedure
This function is defined in SRFI-112 (Environment Inquiry); it returns the CPU architecture, real or virtual, on which this implementation is executing.
STklos procedure
This function is defined in SRFI-112 (Environment Inquiry); it returns a name for the particular machine on which the implementation is running.
STklos procedure
This function is defined in SRFI-112 (Environment Inquiry); it returns the name for the operating system, platform, or equivalent on which the implementation is running.
STklos procedure
This function is defined in SRFI-112 (Environment Inquiry); it returns the version for the operating system, platform, or equivalent on which the implementation is running.
STklos procedure
Returns the system process number of the current program (i.e. the Unix PID as an integer).
4.13.6. Program Arguments Parsing
STklos provides a simple way to parse program arguments with the
parse-arguments
special form. This form is generally used into
the main
| function in a Scheme script. See SRFI-22 (Running Scheme Scripts on Unix) on how to
use a main
function in a Scheme program.
STklos procedure
The parse-arguments
special form is used to parse the
command line arguments of a Scheme script. The implementation of
this form internally uses the GNU C getopt
function. As a
consequence parse-arguments
accepts options which start with
the '-' (short option) or '--' characters (long option).
The first argument of parse-arguments
is a list of the arguments
given to the program (comprising the program name in the CAR of this
list). Following arguments are clauses. Clauses are described later.
By default, parse-arguments
permutes the contents of (a copy) of
the arguments as it scans, so that eventually all the non-options are
at the end. However, if the shell environment variable POSIXLY_CORRECT
is set, then option processing stops as soon as a non-option argument
is encountered.
A clause must follow the syntax:
<clause> => string | <list-clause>
<list clause> => (<option descr> <expr> ...) | (else <expr> ...)
<option descr> => (<option name> [<keyword> value]*)
<option name> => string
<keyword> => :alternate | :arg | :help
A string clause is used to build the help associated to the command.
A list clause must follow the syntax describes an option. The
<expr>
s associated to a list clauses are executed when the option
is recognized.
The else
clauses is executed when all parameters have
been parsed. The :alternate
key permits to have an alternate name for an
option (generally a short or long name if the option name is a
short or long name). The :help
is used to provide help about the
the option. The :arg
is used when the option admit a parameter:
the symbol given after :arg
will be bound to the value of the option
argument when the corresponding `<expr>`s will be executed.
In an else
clause the symbol other-arguments
is bound to the
list of the arguments which are not options.
The following example shows a rather complete usage of the
parse-arguments
form
#!/usr/bin/env stklos
(define (main args)
(parse-arguments args
"Usage: foo [options] [parameter ...]"
"General options:"
(("verbose" :alternate "v" :help "be more verbose")
(printf "Seen the verbose option~%"))
(("long" :help "a long option alone")
(printf "Seen the long option~%"))
(("s" :help "a short option alone")
(printf "Seen the short option~%"))
"File options:"
(("input" :alternate "f" :arg file
:help "use <file> as input")
(printf "Seen the input option with ~S argument~%" file))
(("output" :alternate "o" :arg file
:help "use <file> as output")
(printf "Seen the output option with ~S argument~%" file))
"Misc:"
(("help" :alternate "h"
:help "provides help for the command")
(arg-usage (current-error-port))
(exit 1))
(else
(printf "All options parsed. Remaining arguments are ~S~%"
other-arguments))))
The following program invocation
foo -vs --input in -o out arg1 arg2
produces the following output
Seen the verbose option
Seen the short option
Seen the input option with "in" argument
Seen the output option with "out" argument
All options parsed. Remaining arguments are ("arg1" "arg2")
Finally, the program invocation
foo --help
produces the following output
Usage: foo [options] [parameter ...]
General options:
--verbose, -v be more verbose
--long a long option alone
-s a short option alone
File options:
--input=<file>, -f <file> use <file> as input
--output=<file>, -o <file> use <file> as output
Misc:
--help, -h provides help for the command
Notes:
-
Short option can be concatenated. That is,
prog -abc
is equivalent to the following program call
prog -a -b -c
-
Any argument following a '--' argument is no more considered as an option, even if it starts with a '-' or '--'.
-
Option with a parameter can be written in several ways. For instance to set the output in the
bar
file for the previous example can be expressed as-
--output=bar
, or -
-o bar
, or -
-obar
-
STklos procedure
This procedure is only bound inside a parse-arguments
form.
It pretty prints the help associated to the clauses of the
parse-arguments
form on the given port. If the argument
as-sexpr
is passed and is not #f
, the help strings are
printed on port
as Sexprs. This is useful if the help
strings need to be manipulated by a program.
4.13.7. Misc. System Procedures
STklos procedure
Sends the given string
to the system shell /bin/sh
. The result of
system
is the integer status code the shell returns.
STklos procedure
These procedures execute the command given in str
. The command given
in str
is passed to /bin/sh
. Exec
returns a string which contains
all the characters that the command str
has printed on it’s standard
output, whereas exec-list
returns a list of the lines which constitute
the output of str
.
(exec "echo A; echo B") => "AnBn"
(exec-list "echo A; echo B") => ("A" "B")
STklos procedure
Returns the address of the object obj
as an integer.
STklos procedure
Exits the program with the specified integer return code. If ret-code
is omitted, the program terminates with a return code of 0.
If program has registered exit functions with register-exit-function!
,
they are called (in an order which is the reverse of their call order).
The STklos exit primitive accepts also an
integer value as parameter (R7RS accepts only a boolean).
|
STklos procedure
Terminates the program without running any outstanding
dynamic-wind after procedures and communicates an exit
value to the operating system in the same manner as exit
.
The STklos emergency-exit primitive accepts also an
integer value as parameter (R7RS accepts only a boolean).
|
STklos procedure
Die
prints the given message
on the current error port and exits
the program with the status
value. If status
is omitted, it
defaults to 1.
STklos procedure
This primitive permits to enter a password (character echoing
being turned off). The value returned by get-password
is the entered
password as a string.
STklos procedure
This function registers proc
as an exit function. This function will
be called when the program exits. When called, proc
will be passed one
parmater which is the status given to the exit
function (or 0 if the
programe terminates normally). The result of register-exit-function!
is undefined.
(let* ((tmp (temporary-file-name))
(out (open-output-file tmp)))
(register-exit-function! (lambda (n)
(when (zero? n)
(delete-file tmp))))
out)
4.14. Keywords
Keywords are symbolic constants which evaluate to themselves.
By default, a keyword is a symbol whose first (or last) character is a colon
(":"). Alternatively, to be compatible with other Scheme
implementations, the notation #:foo
is also available to denote
the keyword of name foo
.
Note that the four directives keyword-colon-position-xxx
or the
parameter object ` keyword-colon-position` permit to change the
default behavior. See section~Identifiers for more
information.
STklos procedure
Returns #t
if obj
is a keyword, otherwise returns #f
.
(keyword? 'foo) => #f
(keyword? ':foo) => #t ; depends of keyword-colon-position
(keyword? 'foo:) => #t ; depends of keyword-colon-position
(keyword? '#:foo) => #t ; always
(keyword? :foo) => #t ; depends of keyword-colon-position
(keyword? foo:) => #t ; depends of keyword-colon-position
(keyword? #:foo) => #t ; always
STklos procedure
Builds a keyword from the given s
. The parameter s
must be a symbol
or a string.
(make-keyword "test") => #:test
(make-keyword 'test) => #:test
(make-keyword ":hello") => #::hello
STklos procedure
Returns the name of key
as a string. The result does not contain a colon.
STklos procedure
This function function has been added to be compatibe with SRFI-88. It is equivalent to make-keyword, except that the parameter cannot be a symbol.
STklos procedure
List
must be a list of keywords and their respective values.
key-get
scans the list
and returns the value
associated with the given key
. If key
does
not appear in an odd position in list
, the specified
default
is returned, or an error is raised if no default
was
specified.
(key-get '(#:one 1 #:two 2) #:one) => 1
(key-get '(#:one 1 #:two 2) #:four #f) => #f
(key-get '(#:one 1 #:two 2) #:four) => error
STklos procedure
List
must be a list of keywords and their respective values.
key-set!
sets the value associated to key
in the keyword list.
If the key is already present in list
, the keyword list is
,(emph "physically") changed.
(let ((l (list #:one 1 #:two 2)))
(set! l (key-set! l #:three 3))
(cons (key-get l #:one)
(key-get l #:three))) => (1 . 3)
STklos procedure
List
must be a list of keywords and their respective values.
key-delete
remove the key
and its associated value of the keyword
list. The key can be absent of the list.
key-delete!
does the same job as key-delete
by physically
modifying its list
argument.
(key-delete '(:one 1 :two 2) :two) => (:one 1)
(key-delete '(:one 1 :two 2) :three) => (:one 1 :two 2)
(let ((l (list :one 1 :two 2)))
(key-delete! l :two)
l) => (:one 1)
STklos procedure
This parameter object indicates the convention used by the reader to denote keywords. The allowed values are:
-
none, to forbid a symbol with colon to be interpreted as a keyword,
-
before, to read symbols starting with a colon as keywords,
-
after, to read symbols ending with a colon as keywords,
-
both, to read symbols starting or ending with a colon as keywords.
Note that the notation #:key
is always read as a keyword independently
of the value of keyword-colon-position
. Hence, we have
(list (keyword? ':a)
(keyword? 'a:)
(keyword? '#:a))
=> (#f #f #t) ; if keyword-colon-position is none
=> (#t #f #t) ; if keyword-colon-position is before
=> (#f #t #t) ; if keyword-colon-position is after
=> (#t #t #t) ; if keyword-colon-position is both
4.15. Hash Tables
A hash table consists of zero or more entries, each consisting of a key and a value. Given the key for an entry, the hashing function can very quickly locate the entry, and hence the corresponding value. There may be at most one entry in a hash table with a particular key, but many entries may have the same value.
STklos hash tables grow gracefully as the number of entries increases, so that there are always less than three entries per hash bucket, on average. This allows for fast lookups regardless of the number of entries in a table.
STklos hash tables procedures are identical to the ones
defined in SRFI-69 (Basic Hash Tables). Note that the default comparison function
is eq?
whereas it is equal?
in this SRFI. See
SRFI’s documentation for more information.
STklos procedure
Make-hash-table
admits three different forms. The most general form
admit two arguments. The first argument is a comparison function which
determines how keys are compared; the second argument is a function which
computes a hash code for an object and returns the hash code as a non
negative integer. Objets with the same hash code are stored in an A-list
registered in the bucket corresponding to the key.
If omitted,
-
hash
defaults to thehash-table-hash
procedure (seehash-table-hash
primitive). -
comparison
defaults to theeq?
procedure (seeeq?
primitive)).
Consequently,
(define h (make-hash-table))
is equivalent to
(define h (make-hash-table eq? hash-table-hash))
An interesting example is
(define h (make-hash-table string-ci=? string-length))
which defines a new hash table which uses string-ci=?
for
comparing keys. Here, we use the string-length as a (very simple)
hashing function. Of course, a function which gives a key depending
of the characters composing the string gives a better repartition
and should probably enhance performance. For instance, the following
call to make-hash-table
should return a more efficient, even if
not perfect, hash table:
(make-hash-table
string-ci=?
(lambda (s)
(let ((len (string-length s)))
(do ((h 0) (i 0 (+ i 1)))
((= i len) h)
(set! h
(+ h (char->integer
(char-downcase (string-ref s i)))))))))
Hash tables with a comparison function equal to eq? or
string=? are handled in an more efficient way (in fact, they don’t use
the hash-table-hash function to speed up hash table retrievals).
|
STklos procedure
Returns #t
if obj
is a hash table, returns #f
otherwise.
STklos procedure
Computes a hash code for an object and returns this hash code as a
non-negative integer. A property of hash-table-hash
is that
(equal? x y) => (equal? (hash-table-hash x) (hash-table-hash y)
as the Common Lisp sxhash
function from which this procedure is
modeled.
STklos procedure
Returns hash-table built from the association list
alist
. This function maps the car
of every element in alist
to the cdr
of corresponding elements in alist
. the comparison
and
hash
functions are interpreted as in make-hash-table
. If some key
occurs multiple times in alist
, the value in the first
association will take precedence over later ones.
STklos procedure
Returns an association list built from the entries in hash
.
Each entry in hash
will be represented as a pair whose car
is the
entry’s key and whose cdr
is its value.
the order of pairs in the resulting list is unspecified. |
(let ((h (make-hash-table)))
(dotimes (i 5)
(hash-table-set! h i (number->string i)))
(hash-table->alist h))
=> ((3 . "3") (4 . "4") (0 . "0")
(1 . "1") (2 . "2"))
STklos procedure
Enters an association between key
and value
in the`hash` table.
The value returned by hash-table-set!
is void.
STklos procedure
Returns the value associated with key
in the given hash
table. If no
value has been associated with key
in hash
, the specified thunk
is
called and its value is returned; otherwise an error is raised.
(define h1 (make-hash-table))
(hash-table-set! h1 'foo (list 1 2 3))
(hash-table-ref h1 'foo) => (1 2 3)
(hash-table-ref h1 'bar
(lambda () 'absent)) => absent
(hash-table-ref h1 'bar) => error
(hash-table-set! h1 '(a b c) 'present)
(hash-table-ref h1 '(a b c)
(lambda () 'absent)) => absent
(define h2 (make-hash-table equal?))
(hash-table-set! h2 '(a b c) 'present)
(hash-table-ref h2 '(a b c)) => present
STklos procedure
This function is equivalent to
(hash-table-ref hash key (lambda () default))
STklos procedure
Deletes the entry for key
in hash
, if it exists. Result of
hash-table-delete!
is void.
(define h (make-hash-table))
(hash-table-set! h 'foo (list 1 2 3))
(hash-table-ref h 'foo) => (1 2 3)
(hash-table-delete! h 'foo)
(hash-table-ref h 'foo
(lambda () 'absent) => absent
STklos procedure
Returns #t
if there is any association of key
in
hash
. Returns #f
otherwise.
STklos procedure
Update the value associated to key
in table hash
if key is already in
table with the value (update-fun current-value)
. If no value is
associated to key
, a new entry in the table is first inserted
before updating it (this new entry being the result of calling thunk
).
Note that the expression
(hash-table-update!/default hash key update-fun default)
is equivalent to
(hash-table-update! hash key update-fun (lambda () default))
(let ((h (make-hash-table))
(1+ (lambda (n) (+ n 1))))
(hash-table-update!/default h 'test 1+ 100)
(hash-table-update!/default h 'test 1+)
(hash-table-ref h 'test)) => 102
STklos procedure
Proc
must be a procedure taking two arguments. Hash-table-for-each
calls proc
on each key/value association in hash
, with the key as
the first argument and the value as the second. The value returned by
hash-table-for-each
is void.
The order of application of proc is unspecified.
|
hash-table-walk is another name for hash-table-for-each
(this is the name used in SRFI-69 (Basic Hash Tables).
|
(let ((h (make-hash-table))
(sum 0))
(hash-table-set! h 'foo 2)
(hash-table-set! h 'bar 3)
(hash-table-for-each h (lambda (key value)
(set! sum (+ sum value))))
sum) => 5
STklos procedure
Proc
must be a procedure taking two arguments. Hash-table-map
calls proc
on each key/value association in hash
, with the key as
the first argument and the value as the second. The result of
hash-table-map
is a list of the values returned by proc
, in an
unspecified order.
The order of application of proc is unspecified.
|
(let ((h (make-hash-table)))
(dotimes (i 5)
(hash-table-set! h i (number->string i)))
(hash-table-map h (lambda (key value)
(cons key value))))
=> ((3 . "3") (4 . "4") (0 . "0") (1 . "1") (2 . "2"))
STklos procedure
Returns the keys or the values of hash
.
STklos procedure
This procedure calls func
for every association in hash
with three arguments: the key of the association key, the value
of the association value, and an accumulated value, val
. Val
is
init-value for the first invocation of func
, and for subsequent
invocations of func
, the return value of the previous invocation of
func
. The value final-value
returned by hash-table-fold
is the
return value of the last invocation of func
. The order in which func
is
called for different associations is unspecified.
For instance, the following expression
(hash-table-fold ht (lambda (k v acc) (+ acc 1)) 0)
computes the number of associations present in the ht
hash table.
STklos procedure
Returns a copy of hash
.
STklos procedure
Adds all mappings in hash2
into hash1
and returns the resulting
hash table. This function may modify hash1
destructively.
STklos procedure
Returns the equivalence predicate used for keys in hash
.
STklos procedure
Returns the hash function used for keys in hash
.
STklos procedure
Returns #t
if obj
is an immutable hash table, #f
if it
is a mutable hash table, and raises an error if obj
is not a
hash table.
STklos procedure
If obj
is a hash table, makes it immutable. Otherwise, raises
an error.
STklos procedure
Returns the number of entries in the hash
.
STklos procedure
Prints overall information about hash
, such as the number of entries
it contains, the number of buckets in its hash array, and the utilization
of the buckets. Information is printed on port
. If no port
is given
to hash-table-stats
, information are printed on the current output port
(see current-output-port
primitive).
4.16. Dates and Times
STklos stores dates and times with a compact representation which consists is an integer which represents the number of seconds elapsed since the Epoch (00:00:00 on January 1, 1970, Coordinated Universal Time --UTC). Dates can also be represented with date structures.
R7RS procedure
Returns an inexact number representing the current time on the International Atomic Time (TAI) scale. The value 0.0 represents midnight on January 1, 1970 TAI (equivalent to ten seconds before midnight Universal Time) and the value 1.0 represents one TAI second later.
STklos procedure
Returns the time since the Epoch (that is 00:00:00 UTC, January 1, 1970), measured in seconds in the Coordinated Universal Time (UTC) scale.
This STklos function should not be confused with
the R7RS primitive current-second which returns an inexact number
and whose result is expressed using the International Atomic Time
instead of UTC.
|
STklos procedure
Return the current time as time object. The type can be time-utc
or time-tai
.
If omitted, type
is time-utc
.
To use more time types, such as time-monotonic and time-process , please
load SRFI-19.
|
STklos procedure
Creates a time structure with the given nanosecond
and second
.
If type
is passed, it must be a symbol representing one of the
supported time types (time-tai
, time-utc
, time-monotonic
,
time-process
and time-duration
).
time-monotonic , time-process and time-duration can
be created, but operations on them are only available when SRFI-19 is
loaded.
|
STklos procedure
These are accessors for time structures.
STklos procedure
Return #t
if obj
is a time object, othererwise returns #f
.
STklos procedure
Convert the time object time
into an inexact real number representing
the number of seconds elapsed since the Epoch.
(time->seconds (current-time)) ==> 1138983411.09337
STklos procedure
Converts into a time object the real number x
representing the number
of seconds elapsed since the Epoch.
(seconds->time (+ 10 (time->seconds (current-time))))
==> a time object representing 10 seconds in the future
STklos procedure
Converts t
, which must be of type time-utc
, to the type
time-tai
.
Time-utc→time-tai
creates a new object, while time-utc→time-tai
can use t
to build the returned object.
STklos procedure
Converts t
, which must be of type time-tai
, to the type
time-utc
.
Time-tai→time-utc
creates a new object, while time-tai→time-utc
can use t
to build the returned object.
STklos procedure
Returns the current system date.
STklos procedure
Build a date from its argument. hour
, minute
, second
, nanosecond
default to 0; day
and month
default to 1; year
defaults to 1970.
STklos procedure
Return #t
if obj
is a date, and otherwise returns #f
.
STklos procedure
Return the nanosecond of date d
.
STklos procedure
Return the second of date d
, in the range 0 to 59.
STklos procedure
Return the minute of date d
, in the range 0 to 59.
STklos procedure
Return the hour of date d
, in the range 0 to 23.
STklos procedure
Return the day of date d
, in the range 1 to 31
STklos procedure
Return the month of date d
, in the range 1 to 12
STklos procedure
Return the year of date d
.
STklos procedure
Return the week day of date d
, in the range 0 to 6 (0 is Sunday).
STklos procedure
Return the the number of days since January 1 of date d
, in the range
1 to 366.
STklos procedure
Return an indication about daylight saving adjustment of date d
:
-
0 if no daylight saving adjustment
-
1 if daylight saving adjustment
-
-1 if the information is not available
STklos procedure
Return the time zone of date d
.
STklos procedure
Returns the local timezone offset, in seconds.
For example, for GMT+2 it will be 2 * 60 * 60
= 7200
(local-timezone-offset) => 0 ;; for GMT
(local-timezone-offset) => 7200 ;; for GMT+2
(local-timezone-offset) => -10800 ;; for GMT-3
The timezone is searched for in the environment variable TZ
. If this
variable does not appear in the environment, the system timezone is used.
STklos procedure
Convert the date d
to the number of seconds since the Epoch,
1970-01-01 00:00:00 +0000 (UTC).
(date->seconds (make-date 0 37 53 1 26 10 2012 0)) => 1351216417.0
STklos procedure
Convert the date d
using the string format
as a
specification. Conventions for format are the same as the one
of primitive seconds→string
.
If format
is omitted, it defaults to "~c"
.
STklos procedure
Convert the date n
expressed as a number of seconds since the Epoch,
1970-01-01 00:00:00 +0000 (UTC) into a date.
n
can be an exact integer or an inexact real.
This is equivalent to converting time-UTC to date.
(seconds->date 1351216417) => #[date 2012-10-26 1:53:37]
STklos procedure
Convert a date expressed in seconds using the string format
as a
specification. Conventions for format
are given below:
-
~~ a literal ~
-
~a locale’s abbreviated weekday name (Sun…Sat)
-
~A locale’s full weekday name (Sunday…Saturday)
-
~b locale’s abbreviate month name (Jan…Dec)
-
~B locale’s full month day (January…December)
-
~c locale’s date and time (e.g., ,(code "Fri Jul 14 20:28:42-0400 2000"))
-
~d day of month, zero padded (01…31)
-
~D date (mm/dd/yy)
-
~e day of month, blank padded ( 1…31)
-
~f seconds+fractional seconds, using locale’s decimal separator (e.g. 5.2).
-
~h same as ~b
-
~H hour, zero padded, 24-hour clock (00…23)
-
~I hour, zero padded, 12-hour clock (01…12)
-
~j day of year, zero padded
-
~k hour, blank padded, 24-hour clock (00…23)
-
~l hour, blank padded, 12-hour clock (01…12)
-
~m month, zero padded (01…12)
-
~M minute, zero padded (00…59)
-
~n new line
-
~p locale’s AM or PM
-
~r time, 12 hour clock, same as "~I:~M:~S ~p"
-
~s number of full seconds since the epoch (in UTC)
-
~S second, zero padded (00…61)
-
~t horizontal tab
-
~T time, 24 hour clock, same as "~H:~M:~S"
-
~U week number of year with Sunday as first day of week (00…53)
-
~V weekISO 8601:1988 week number of year (01…53) (week 1 is the first week that has at least 4 days in the current year, and with Monday as the first day of the week)
-
~w day of week (1…7, 1 is Monday)
-
~W week number of year with Monday as first day of week (01…52)
-
~x week number of year with Monday as first day of week (00…53)
-
~X locale’s date representation, for example: "07/31/00"
-
~y last two digits of year (00…99)
-
~Y year
-
~z time zone in RFC-822 style
-
~Z symbol time zone
STklos procedure
Returns a keyword list for the date given by sec
(a date based on the
Epoch). The keyed values returned are
-
nanosecond : 0 to 999999
-
second : 0 to 59 (but can be up to 61 to allow for leap seconds)
-
minute : 0 to 59
-
hour : 0 to 23
-
day : 1 to 31
-
month : 1 to 12
-
year : e.g., 2002
-
week-day : 0 (Sunday) to 6 (Saturday)
-
year-day : 0 to 365 (365 in leap years)
-
dst : indication about daylight savings time (see primitive
date-dst
). -
tz : the difference between Coordinated Universal Time (UTC) and local standard time in seconds.])
(seconds->list (current-second))
=> (#:nanosecond 182726 #:second 21 #:minute 35 #:hour 20 #:day 10 #:month 1
#:year 2022 #:week-day 1 #:year-day 10 #:dst 0 #:tz -3600)
STklos procedure
Returns the current date in a string.
4.17. Boxes
Boxes are objects which contain one or several states. A box may be constructed with the box, constant-box. STklos boxes are compatible with the one defined in SRFI-111 (Boxes) or SRFI-195 (Multiple-value boxes). Boxes of SRFI-111 can contain only one value, whereas SRFI-195 boxes can contain multiple values. Furthermore, STklos defines also the notion of constant boxes which are not mutable.
The read primitive can also make single valued boxes (using the #&
notation). Such boxes are mutable.
Note that two boxes are equal?
iff their content are equal?
.
STklos procedure
Returns a new box that contains all the given `value`s. The box is mutable.
(let ((x (box 10)))
(list 10 x)) => (10 #&10)
The name make-box is now obsolete and kept only for compatibility.
|
STklos procedure
Returns a new box that contains all the given `value`s. The box is immutable.
The name make-constant-box is now obsolete and kept only for compatibility.
|
STklos procedure
Returns #t
if obj
is a box, #f
otherwise.
STklos procedure
Returns #t
if obj
is a mutable box, #f
otherwise.
STklos procedure
Changes box
to hold value`s. It is an error if `set-box!
is called
with a number of values that differs from the number of values in the box
being set. (In other words, set-box!
does not allocate memory.)
It is also an error to call set-box!
on a box which is not mutable.
The name box-set!
is now obsolete and kept only for compatibility.
STklos procedure
Returns the values currently in box
.
STklos procedure
Returns the number of values in box
.
STklos procedure
Returns the i
th value of box
. It is an error if i
is not an exact integer
between 0 and n
-1, when n
is the number of values in box
.
STklos procedure
Changes the i
th value of box
to obj
. It is an error if i
is not an
exact integer between 0 and n
-1, when n
is the number of values in box
.
4.18. Processes
STklos provides access to Unix processes as first class objects. Basically, a process contains information such as the standard system process identification (aka PID on Unix Systems), the files where the standard files of the process are redirected, …
STklos procedure
run-process
creates a new process and run the executable
specified in command
. The p
correspond to the command line
arguments. The following values of p
have a special meaning:
-
:input
permits to redirect the standard input file of the process. Redirection can come from a file or from a pipe. To redirect the standard input from a file, the name of this file must be specified after:input
. Use the special keyword:pipe
to redirect the standard input from a pipe. -
:output
permits to redirect the standard output file of the process. Redirection can go to a file or to a pipe. To redirect the standard output to a file, the name of this file must be specified after:output
. Use the special keyword:pipe
to redirect the standard output to a pipe. -
:error
permits to redirect the standard error file of the process. Redirection can go to a file or to a pipe. To redirect the standard error to a file, the name of this file must be specified aftererror
. Use the special keyword:pipe
to redirect the standard error to a pipe. -
:wait
must be followed by a boolean value. This value specifies if the process must be run asynchronously or not. By default, the process is run asynchronously (i.e.:wait
is#f
). -
:host
must be followed by a string. This string represents the name of the machine on which the command must be executed. This option uses the external commandrsh
. The shell variablePATH
must be correctly set for accessing it without specifying its abolute path. -
:fork
must be followed by a boolean value. This value specifies if a fork" system call must be done before running the process. If the process is run without fork the Scheme program is lost. This feature mimics the``exec’' primitive of the Unix shells. By default, a fork is executed before running the process (i.e. `:fork
is#t
). This option works on Unix implementations only.
The following example launches a process which executes the
Unix command ls
with the arguments -l
and /bin
. The lines
printed by this command are stored in the file /tmp/X
(run-process "ls" "-l" "/bin" :output "/tmp/X")
STklos procedure
Returns #t
if obj
is a process , otherwise returns #f
.
STklos procedure
Returns #t
if process proc
is currently running, otherwise returns #f
.
STklos procedure
Returns an integer which represents the Unix identification (PID) of the processus.
STklos procedure
Returns the file port associated to the standard input, output or error
of proc
, if it is redirected in (or to) a pipe; otherwise
returns #f
. Note that the returned port is opened for reading
when calling process-output
or process-error
; it is opened
for writing when calling process-input
.
STklos procedure
Stops the current process (the Scheme process) until proc
completion.
Process-wait
returns #f
when proc
is already terminated; it returns
#t
otherwise.
STklos procedure
Returns the exit status of proc
if it has finished its execution;
returns #f
otherwise.
STklos procedure
Sends the integer signal sig
to proc
. Since value of sig
is system
dependant, use the symbolic defined signal constants to make your program
independant of the running system (see Section 4.20).
The result of process-send-signal
is void.
STklos procedure
Kills (brutally) process
. The result of process-kill
is void. This procedure is equivalent to
(process-send-signal process SIGTERM)
STklos procedure
Process-stop
stops the execution of proc
and process-continue
resumes
its execution. They are equivalent, respectively, to
(process-send-signal process SIGSTOP)
(process-send-signal process SIGCONT)
STklos procedure
Returns the list of processes which are currently running (i.e. alive).
STklos procedure
This procedure is a wrapper around the standard Unix fork
system
call which permits to create a new (heavy) process.
When called without parameter, this procedure returns two times
(one time in the parent process and one time in the child process).
The value returned to the parent process is a process object
representing the child process and the value returned to the child
process is always the value #f
.
When called with a parameter (which must be a thunk), the new process
excutes thunk
and terminate it execution when thunk
returns. The
value returned to the parent process is a process object representing
the child process.
4.19. Sockets
STklos defines sockets, on systems which support them, as first class objects. Sockets permits processes to communicate even if they are on different machines. Sockets are useful for creating client-server applications.
STklos procedure
make-client-socket
returns a new socket object. This socket
establishes a link between the running program and the application
listening on port port-number
of hostname
. If the optional argument
line-buffered
has a true value, a line buffered policy is used when writing
to the client socket (i.e. characters on the socket are tranmitted as soon
as a "#newline
character is encountered). The default value of
line-buffered
is #t
.
STklos procedure
make-server-socket
returns a new socket object. If port-number
is specified, the socket is listening on the specified port;
otherwise, the communication port is chosen by the system.
STklos procedure
Socket-shutdown
shutdowns the connection associated to
socket
. If the socket is a server socket, socket-shutdown
is called
on all the client sockets connected to this server.
Close
indicates if the socket must be closed or not, when
the connection is destroyed. Closing the socket forbids further
connections on the same port with the socket-accept
procedure.
Omitting a value for close
implies the closing of socket.
The following example shows a simple server: when there is a new connection on the port number 12345, the server displays the first line sent to it by the client, discards the others and go back waiting for further client connections.
(let ((s (make-server-socket 12345)))
(let loop ()
(let ((ns (socket-accept s)))
(format #t "I've read: ~A\n"
(read-line (socket-input ns)))
(socket-shutdown ns #f)
(loop))))
STklos procedure
socket-accept
waits for a client connection on the given
socket
. If no client is already waiting for a connection, this
procedure blocks its caller; otherwise, the first connection request
on the queue of pending connections is connected and socket-accept
returns a new client socket to serve this request.
This procedure must be called on a server socket created
with make-server-socket
. The result of socket-accept
is undefined.
Line-buffered
indicates if the port should be considered as a
line buffered. If line-buffered
is omitted, it defaults to #t
.
The following example is a simple server which waits for a connection on the port 12345 [4]
Once the connection with the distant program is established, we read a line on the input port associated to the socket, and we write the length of this line on its output port.
(let* ((server (make-server-socket 12345))
(client (socket-accept server))
(l (read-line (socket-input client))))
(format (socket-output client)
"Length is: ~an" (string-length l))
(socket-shutdown server))
Note that shutting down the server
socket suffices here to close
also the connection to client
.
STklos procedure
Returns #t
if socket
is a socket, otherwise returns #f
.
STklos procedure
Returns #t
if socket
is a server socket, otherwise returns #f
.
STklos procedure
Returns #t
if socket
is a client socket, otherwise returns #f
.
STklos procedure
Returns a string which contains the name of the distant host
attached to socket
. If socket
has been created with
make-client-socket
this procedure returns the official name of
the distant machine used for connection. If socket
has been
created with make-server-socket
, this function returns the
official name of the client connected to the socket. If no client
has used yet socket
, this function returns #f
.
STklos procedure
Returns a string which contains the IP number of the distant host
attached to socket
. If socket
has been created with
make-client-socket
this procedure returns the IP number of the
distant machine used for connection. If socket
has been created
with make-server-socket
, this function returns the address of the
client connected to the socket. If no client has used yet
socket
, this function returns #f
.
STklos procedure
Returns a string which contains the IP number of the local host
attached to socket
.
STklos procedure
Returns the integer number of the port used for socket
.
STklos procedure
Returns the port associated for reading or writing with the
program connected with socket
. Note that this port is both textual
and binary. If no connection has already been established,
these functions return #f
.
The following example shows how to make a client socket. Here we
create a socket on port 13 of the machine
kaolin.unice.fr
[5]:
(let ((s (make-client-socket "kaolin.unice.fr" 13)))
(format #t "Time is: ~A~%" (read-line (socket-input s)))
(socket-shutdown s))
4.20. Signals
STklos permits to associate handlers to POSIX.1 signals. When a signal handler is called, the integer value of this signal is passed to it as (the only) parameter.
The following POXIX.1 values for signal numbers are defined:
SIGABRT
SIGALRM
, SIGFPE
, SIGHUP
,SIGILL
, SIGINT
, SIGKILL
,
SIGPIPE
, SIGQUIT
, SIGSEGV
, SIGTERM
, SIGUSR1
, SIGUSR2
,
SIGCHLD
, SIGCONT
, SIGSTOP
, SIGTSTP
, SIGTTIN
, SIGTTOU
.
Moreover, the following constants, which are often available on most
systems are also defined (if supported by the running system):
SIGTRAP
, SIGIOT
, SIGEMT
, SIGBUS
, SIGSYS
, SIGURG
, SIGCLD
,
SIGIO
, SIGPOLL
, SIGXCPU
, SIGXFSZ
, SIGVTALRM
, SIGPROF
,
SIGWINCH
, SIGLOST
.
See your Unix documentation for the exact meaning of each constant or [POSIX]. Use symbolic constants rather than their numeric value if you plan to port your program on another system.
STklos procedure
Replace the handler for integer signal sig
with handler
.
The value of handler
can be:
-
#t
to reset the signal handler forsig
to the default system handler. -
#f
to ignore thesig
signal. Note that POSIX states thatSIGKILL
andSIGSTOP
cannot be ignored or caught. -
a one parameter procedure, which will be called when the processus receives the signal
sig
.
This procedure returns void.
(let ((x #f))
(set-signal-handler! SIGUSR1
(lambda (i) (set! x #t)))
(send-signal SIGUSR1)
x) => #t
STklos procedure
Return the handler for integer signal sig
.
The value of handler
can be a boolean value or a procedure.
See primitive set-signal-handler!
for
more information.
STklos procedure
Send the integer signal sig
to the process with pid
process id.
If the second parameter is absent, it deaults to the one of the running
program.
STklos procedure
Pauses the STklos process until the delivery of a signal whose action
is either to execute a signal-catching function or to terminate the
process. If the action is to terminate the process, pause
will not
return. If the action is to execute a signal-catching function, pause
will terminate after the signal-catching function returns.
4.21. Parameter Objects
STklos parameters correspond to the ones defined in SRFI-39 (Parameters objects). See SRFI document for more information.
STklos procedure
Returns a new parameter object which is bound in the global dynamic
environment to a cell containing the value returned by the call
(converter init)
. If the conversion procedure converter
is not
specified the identity function is used instead.
The parameter object is a procedure which accepts zero or one
argument. When it is called with no argument, the content of the
cell bound to this parameter object in the current dynamic
environment is returned. When it is called with one argument, the
content of the cell bound to this parameter object in the current
dynamic environment is set to the result of the call
(converter arg)
, where arg
is the argument passed to the
parameter object, and an unspecified value is returned.
(define radix
(make-parameter 10))
(define write-shared
(make-parameter
#f
(lambda (x)
(if (boolean? x)
x
(error 'write-shared "bad boolean ~S" x)))))
(radix) => 10
(radix 2)
(radix) => 2
(write-shared 0) => error
(define prompt
(make-parameter
123
(lambda (x)
(if (string? x)
x
(with-output-to-string (lambda () (write x)))))))
(prompt) => "123"
(prompt ">")
(prompt) => ">"
STklos syntax
The expressions expr1
and expr2
are evaluated in an unspecified order.
The value of the expr1
expressions must be parameter objects.
For each expr1
expression and in an unspecified order, the local
dynamic environment is extended with a binding of the parameter object
expr1
to a new cell whose content is the result of the call
(converter val)
, where val
is the value of expr2
and converter
is the conversion procedure of the parameter object. The resulting
dynamic environment is then used for the evaluation of <body>
(which refers to the R5RS grammar nonterminal of that name).
The result(s) of the parameterize form are the result(s) of
the <body>
.
(radix) => 2
(parameterize ((radix 16)) (radix)) => 16
(radix) => 2
(define (f n) (number->string n (radix)))
(f 10) => "1010"
(parameterize ((radix 8)) (f 10)) => "12"
(parameterize ((radix 8) (prompt (f 10))) (prompt)) => "1010"
STklos procedure
Returns #t
if obj
is a parameter object, otherwise returns #f
.
4.22. Misc
STklos procedure
Force a garbage collection step.
STklos procedure
Returns the special void object. If arguments are passed to void
,
they are evalued and simply ignored.
STklos procedure
Returns #t
if obj
is #void
, and #f
otherwise.
The usual "unspecified" result in Scheme standard and in SRFIs is #void
in STklos, and it is also returned by the procedure void
.
(void? (void)) => #t
(define x (if #f 'nope))
(void? x) => #t
(void? '()) => #f
(void? 'something) => #f
(void? (for-each print '(1 2 3))) => #t
R7RS procedure
error
is used to signal an error to the user. The second form
of error
takes a symbol as first parameter; it is generally used for the
name of the procedure which raises the error.
R7RS permits only the fist form of call. Using a symbol as first
parameter is STklos specific.
Furthermore, the specification string may follow the tilde conventions of
format (see primitive format ); in this case this
procedure builds an error message according to the specification
given in str . Otherwise,
this procedure is in conformance with the error procedure defined in
SRFI-23 (Error reporting mechanism) and str is printed with the display procedure,
whereas the obj parameters are printed with the write procedure.
|
Hereafter, are some calls of the error
procedure using a formatted string
(error "bad integer ~A" "a")
|- bad integer a
(error 'vector-ref "bad integer ~S" "a")
|- vector-ref: bad integer "a"
(error 'foo "~A is not between ~A and ~A" "bar" 0 5)
|- foo: bar is not between 0 and 5
and some conform to SRFI-23
(error "bad integer" "a")
|- bad integer "a"
(error 'vector-ref "bad integer" "a")
|- vector-ref: bad integer "a"
(error "bar" "is not between" 0 "and" 5)
|- bar "is not between" 0 "and" 5
STklos procedure
This procedure is similar to error, except that the type of the error
can be passed as the first parameter. The type of the error must be a
condition which inherits from &error-message
.
Note that (error arg …)
is equivalent to
(signal-error &error-message arg ...)
R7RS syntax
Syntax-error
behaves similarly to error
except that it signals the
error as soon as syntax-error is expanded. This can be use in macros to signal
errors at compile time, without interrupting the compilation process. In
interactive mode, under the REPL, syntax-error
yields a true error.
R7RS defines only the first form of call (with a string as first
parameter). STklos permits to use a symbol as first parameter to specify the
location of the syntax error. It also permits the usage of tilde conventions
as the error primitive.
|
R7RS procedure
Error type predicates. Returns #t
if obj
is an object raised
by the read procedure or by the inability to open an input or
output port on a file, respectively. Otherwise, it returns #f
.
R7RS procedure
Returns #t
if obj
is an object created by error. Otherwise,
it returns #f
.
R7RS procedure
Returns the message encapsulated by error-object
.
R7RS procedure
Returns the message encapsulated by error-object
.
STklos procedure
Returns the location encapsulated by error-object
if it exists.
Returns #f
otherwise. The location corresponds generally to the name
of the procedure which raised the error.
(guard (cnd
(else (error-object-location cnd)))
(error 'foo "error message")) => foo
STklos syntax
The syntax of require-extension is as follows:
(require-extension <clause> ...)
A clause may have the form:
-
(srfi number …)
-
(identifier …)
-
identifier
In the first form the functionality of the indicated SRFIs are made
available in the context in which the require-extension
form appears.
For instance,
(require-extension (srfi 1 2)) ; Make the SRFI 1 and 2 available
This form is compatible with SRFI-55 (Require-extension).
The second and third forms are STklos extensions. If the form is a list, it is equivalent to an import. That is,
(require-extension (streams primitive) (streams derived))
is equivalent to
(import (streams primitive) (streams derived))
The final form permits to use symbolic names for requiring some extensions. For instance,
(require-extension lists and-let*)
is equivalent to the requiring srfi-1
and srfi-2
.
A list of available symbolic names for features is given in Chapter 13.
STklos procedure
This primitive ensures that the feature
(in sense of SRFI-0 feature)
can be used. In particular, it eventually requires the loading of the
files needed to used feature
. The feature
can be expressed as a
string or a symbol, If feature is an integer n
, it is equivalent to srfi-n
.
Consequently, to use SRFI-1 the following forms are equivalent:
(require-feature 'srfi-1)
(require-feature "srfi-1")
(require-feature 1)
(require-feature 'lists) ;; Since this feature name is an alias for SRFI-1
See also Chapter 13 for more information.
STklos procedure
This procedure launches a new Read-Eval-Print-Loop. Calls to repl
can be
embedded. The ports used for input/output as well as the error port can
be passed when repl
is called. If not passed, they default to
current-input-port
, current-output-port
and current-error-port
.
STklos syntax
The special form assume
is defined in SRFI-145 (Assumptions).
When STklos is in debug mode, this special form is an expression
that evaluates to the value of obj
if obj
evaluates to a true
value and it is an error if obj
evaluates to a false value.
When STklos is not in debug mode, the call to assume
is elided.
STklos procedure
This function returns an association list of STklos properties as defined by SRFI-176 (Version flag).
STklos procedure
Apropos
returns a list of symbols whose print name contains the
characters of obj
as a substring . The given obj
can be a string or
symbol. This function returns the list of matched symbols which can
be accessed from the given module
(defaults to the current module if not
provided).
STklos procedure
When called with an argument, help
tries to give some help on the
given object, which could be a symbol, a procedure, a generic function
or a method. Whe called called without arguments, help
enters a
read-help-print loop. The documentation for an object is searched in
the object itself or, if absent, in STklos documentation. Inserting
the documentation in an objet is very similar to Emacs docstrings: a
documentation string is defined among the code. Exemples of such
strings are given below
(define (foo n)
"If the function body starts with a string, it's a docstring"
(+ n 1))
(define-generic bar
:documentation "Generic function docsting for bar")
(define-method bar ((x <integer>))
"Probably less useful: as in functions, methods can have docstrings"
(- x 1))
STklos procedure
Shows a brief description of obj
. If the object is structured
such as a struct, class or instance, some information about its
internal structure will be shown.
Using describe
on simple values
(describe 5)
5 is an integer.
(describe 5.4)
5.4 is a real.
(describe 2+3i)
2+3i is a complex number.
(describe #A)
#A is a character, ascii value is 65.
Using describe
on a class
(describe <integer>)
<integer> is a class. It's an instance of <class>.
Superclasses are:
<rational>
(No direct slot)
(No direct subclass)
Class Precedence List is:
<integer>
<rational>
<real>
<complex>
<number>
<top>
(No direct method)
Using describe
on structures
(define-struct person name email)
(define one (make-person "Some One" "one@domain.org"))
(describe person)
#[struct-type person 139786494092352] is a structure type whose name is person.
Parent structure type: #f
Slots are:
name
email
(describe one)
#[struct person 139786494288064] is an instance of the structure type person.
Slots are:
name = "Some One"
email = "one@domain.org"
STklos syntax
Invoking trace
with one or more function names causes the functions
named to be traced. Henceforth, whenever such a function is invoked,
information about the call and the returned values, if any, will be
printed on the current error port.
Calling trace
with no argument returns the list of traced functions.
STklos syntax
Invoking untrace
with one or more function names causes the functions
named not to be traced anymore.
Calling untrace
with no argument will untrace all the functions
currently traced.
STklos procedure
This function tries to obtain a pretty-printed representation of sexpr
.
The pretty-printed form is written on port
with lines which are no
more long than width
characters. If port
is omitted if defaults to
the current error port. As a special convention, if port
is #t
,
output goes to the current output port and if port
is #f
, the output
is returned as a string by pretty-print
.
Note that pp
is another name for pretty-print
.
STklos procedure
Returns the formal parameters of procedure proc
.
Note that procedure formal parameters are kept in memory only if
the compiler flag <<"compiler:keep-formals">> is set at its creation.
If proc
formal parameters are not available, procedure-formals
returns #f
.
STklos procedure
Returns the source form used to define procedure proc
.
Note that procedure source is kept in memory only if the compiler flag
<<"compiler:keep-source">> is set at its creation. If proc
source is
not available, procedure-source
returns #f
.
STklos procedure
ansi-color
permits to build a string which embeds ANSI codes to
colorize texts on a terminal. Each expression ei must be a string,
a symbol or an integer.
Strings constitute the message to be displayed.
A symbol can designate
-
a color in the set {
black
,red
,green
,yellow
,blue
,magenta
,cyan
,white
} for foreground colors -
a color in the set {
bg-black
,bg-red
,bg-green
,bg-yellow
,bg-blue
,bg-magenta
,bg-cyan
,bg-white
} for background colors. -
a qualifier such as
normal
,bold
,italic
,underline
,blink
,reverse
orno-bold
,no-italic
,no-underline
,no-blink
,no-reverse
.
Integer values can be used for terminals which are able to display 256 colors. If the number is positive, it is used as a foreground color. Otherwise, it is uses as a background color. Note that not all the terminals are able to use more than eight colors.
For instance,
(display (ansi-color "a word in "
'bold 'red "RED" 'normal
" and another in "
'reverse 'blue "BLUE" 'normal))
will display the words BLUE and RED in color.
STklos procedure
This function prints on the given port (by default the current output
port) the instructions of procedure proc
. The printed code uses an
ad-hoc instruction set that should be quite understandable.
(define (fact n)
(if (< n 2)
1
(* n (fact (- n 1)))))
The call (disassemble fact)
will produce the following output:
000: LOCAL-REF0-PUSH
001: SMALL-INT 2
003: JUMP-NUMGE 2 ;; ==> 007
005: IM-ONE
006: RETURN
007: LOCAL-REF0-PUSH
008: PREPARE-CALL
009: LOCAL-REF0
010: IN-SINT-ADD2 -1
012: PUSH-GREF-INVOKE 0 1
015: IN-MUL2
016: RETURN
The code of a procedure may be patched after the first execution
of proc to optimize it.
|
If proc
is an anonymous function, you can use the special
notation #pxxx
to disassemble it:
*
(disassemble #p7fee1dd82f80) ;; (address-of (lambda() 42))
000: SMALL-INT 42
002: RETURN
STklos procedure
This function prints on the given port
(by default the current output
port) the instructions of the given sexpr
. If show-consts
is true,
the table of the contants used in sexpr
is also printed.
(disassemble-expr '(begin
(define x (+ y 10))
(cons x y))
#t)
will print:
000: GLOBAL-REF 0
002: IN-SINT-ADD2 10
004: DEFINE-SYMBOL 1
006: GLOBAL-REF-PUSH 1
008: GLOBAL-REF 0
010: IN-CONS
011:
Constants:
0: y
1: x
STklos procedure
Parses the string str
as an RFC-2396 URI and return a keyed list with the
following components
-
scheme
: the scheme used as a string (defaults to"file"
) -
user
: the user information (generally expressed aslogin:password
) -
host
: the host as a string (defaults to "") -
port
: the port as an integer (0 if no port specified) -
path
: the path -
query
: the qury part of the URI as a string (defaults to the empty string) -
fragment
: the fragment of the URI as a string (defaults to the empty string)
(uri-parse "https://stklos.net")
=> (:scheme "https" :user "" :host "stklos.net" :port 443
:path "/" :query "" :fragment "")
(uri-parse "https://stklos.net:8080/a/file?x=1;y=2#end")
=> (:scheme "http" :user "" :host "stklos.net" :port 8080
:path "/a/file" :query "x=1;y=2" :fragment "end")
(uri-parse "http://foo:secret@stklos.net:2000/a/file")
=> (:scheme "http" :user "foo:secret" :host "stklos.net"
:port 2000 :path "/a/file" :query "" :fragment "")
(uri-parse "/a/file")
=> (:scheme "file" :user "" :host "" :port 0 :path "/a/file"
:query "" :fragment "")
(uri-parse "")
=> (:scheme "file" :user "" :host "" :port 0 :path ""
:query "" :fragment "")
STklos procedure
This primitive is a convenience function; it returns a string where the HTML special chars are properly translated. It can easily be written in Scheme, but this version is fast.
(string->html "Just a <test>")
=> "Just a <test>"
STklos procedure
Return a string contening the md5 sum of obj
. The given parameter can
be a string or an open input port.
STklos procedure
Return a string contening the md5 sum of the file whose name is str
.
STklos procedure
Encode in Base64 the characters from input port in
to the output port
out
. If out
is not specified, it defaults to the current output port.
(with-input-from-string "Hello"
(lambda ()
(with-output-to-string
(lambda ()
(base64-encode (current-input-port)))))) => "SGVsbG8="
STklos procedure
Decode the Base64 characters from input port in
to the output port
out
. If out
is not specified, it defaults to the current output port.
(with-input-from-string "SGVsbG8="
(lambda ()
(with-output-to-string
(lambda ()
(base64-decode (current-input-port)))))) => "Hello"
STklos procedure
Return a string contening the contents of str
converted to Base64
encoded format.
STklos procedure
Decode the contents of str
expressed in Base64.
5. Regular Expressions
STklos uses the Philip Hazel’s Perl-compatible Regular Expression (PCRE) library for implementing regexps [PCRE]. Consequently, the STklos regular expression syntax is the same as PCRE, and Perl by the way.
The following text is extracted from the PCRE package. However, to make things shorter, some of the original documentation as not been reported here. In particular some possibilities of PCRE have been completely occulted (those whose description was too long and which seems (at least to me), not too important). Read the documentation provided with PCRE for a complete description footnote{The latest release of PCRE is available from http://www.pcre.org/.
A regular expression is a pattern that is matched against a subject string from left to right. Most characters stand for themselves in a pattern, and match the corresponding characters in the subject. As a trivial example, the pattern
The quick brown fox
matches a portion of a subject string that is identical to itself. The power of regular expressions comes from the ability to include alternatives and repetitions in the pattern. These are encoded in the pattern by the use of meta-characters, which do not stand for themselves but instead are interpreted in some special way.
There are two different sets of meta-characters: those that are recognized anywhere in the pattern except within square brackets, and those that are recognized in square brackets. Outside square brackets, the meta-characters are as follows:
general escape character with several uses |
|
^ |
assert start of subject (or line, in multiline mode) |
$ |
assert end of subject (or line, in multiline mode) |
. |
match any character except newline (by default) |
[ |
start character class definition |
start of alternative branch |
( |
start subpattern |
) |
end subpattern |
? |
extends the meaning of '(' |
* |
0 or more quantifier |
+ |
1 or more quantifier |
{ |
Part of a pattern that is in square brackets is called a "character class". In a character class the only meta-characters are:
general escape character |
|
^ |
negate the class, but only if the first character |
- |
indicates character range |
[ |
POSIX character class (only if followed by POSIX syntax) |
] |
terminates the character class |
The following sections describe the use of each of the meta-characters.
5.1. Backslash
The backslash character has several uses. Firstly, if it is followed by a non-alphameric character, it takes away any special meaning that character may have. This use of backslash as an escape character applies both inside and outside character classes.
For example, if you want to match a character, you write
in the pattern. This escaping action applies whether or not
the following character would otherwise be interpreted as a
meta-character, so it is always safe to precede a non-alphameric
with backslash to specify that it stands for itself. In
particular, if you want to match a backslash, you write
\
.
If you want to remove the special meaning from a sequence of characters, you
can do so by putting them between Q
and E
. This is different from Perl
in that $
and @
are handled as literals in Q
…E
sequences in PCRE,
whereas in Perl, `$
and @
cause variable interpolation. Note the following
examples:
Pattern | PCRE matches | Perl matches |
---|---|---|
Qabc$xyzE |
abc$xyz |
abc followed by the contents of $xyz |
Qabc$xyzE |
abc$xyz |
abc$xyz |
QabcE$QxyzE |
abc$xyz |
abc$xyz |
The Q…E
sequence is recognized both inside and outside character
classes.
A second use of backslash provides a way of encoding non-printing characters in patterns in a visible manner. There is no restriction on the appearance of non-printing characters, apart from the binary zero that terminates a pattern, but when a pattern is being prepared by text editing, it is usually easier to use one of the following escape sequences than the binary character it represents:
a |
alarm, that is, the BEL character (hex 07) |
cx |
control-x, where x is any character |
e |
escape (hex 1B) |
f |
formfeed (hex 0C) |
n |
newline (hex 0A) |
r |
carriage return (hex 0D) |
t |
tab (hex 09) |
ddd |
character with octal code ddd, or backreference |
xhh |
character with hex code hh |
The precise effect of x
is as follows: if x
is a lower case
letter, it is converted to upper case. Then bit 6 of the character
(hex 40) is inverted. Thus cz
becomes hex 1A, but c{
becomes
hex 3B, while c;
becomes hex 7B.
The handling of a backslash followed by a digit other than 0 is complicated. Outside a character class, PCRE reads it and any following digits as a decimal number. If the number is less than 10, or if there have been at least that many previous capturing left parentheses in the expression, the entire sequence is taken as a back reference. A description of how this works is given later, following the discussion of parenthesized subpatterns.
The third use of backslash is for specifying generic character types:
d |
any decimal digit |
D |
any character that is not a decimal digit |
s |
any whitespace character |
S |
any character that is not a whitespace character |
w |
any word character |
W |
any non-word character |
Each pair of escape sequences partitions the complete set of characters into two disjoint sets. Any given character matches one, and only one, of each pair.
For compatibility with Perl, s
does not match the VT character
(code 11). This makes it different from the the POSIX "space"
class. The s
characters are HT (9), LF (10), FF (12), CR (13), and
space (32).
A word character is any letter or digit or the underscore character,
that is, any character which can be part of a Perl word. The
definition of letters and digits is controlled by PCRE’s character
tables, and may vary if locale-specific matching is taking place. For
example, in the "fr" (French) locale, some character codes greater
than 128 are used for accented letters, and these are matched by w
.
These character type sequences can appear both inside and outside character classes. They each match one character of the appropriate type. If the current matching point is at the end of the subject string, all of them fail, since there is no character to match.
The fourth use of backslash is for certain simple assertions. An assertion specifies a condition that has to be met at a particular point in a match, without consuming any characters from the subject string. The use of subpatterns for more complicated assertions is described below. The backslashed assertions are
b |
matches at a word boundary |
B |
matches when not at a word boundary |
A |
matches at start of subject |
Z |
matches at end of subject or before newline at end |
z |
matches at end of subject |
G |
matches at first matching position in subject |
These assertions may not appear in character classes (but note that
b
has a different meaning, namely the backspace character, inside a
character class).
A word boundary is a position in the subject string where the current
character and the previous character do not both match w
or W
(i.e. one matches w
and the other matches
W
), or the start or end of the string if the first or last
character matches w
, respectively.
The A
, Z
, and z
assertions differ from the traditional
circumflex and dollar (described below) in that they only ever match
at the very start and end of the subject string, whatever options
are set. Thus, they are independent of multiline mode.
The backslash character has several uses. Firstly, if it is followed by a non-alphameric character, it takes away any special meaning that character may have. This use of backslash as an escape character applies both inside and outside character classes.
For example, if you want to match a "" character, you write "\" in the pattern. This applies whether or not the following character would otherwise be interpreted as a meta-character, so it is always safe to precede a non-alphameric with “`" to specify that it stands for itself. In particular, if you want to match a backslash, you write "`\”.
5.2. Circumflex and Dollar
Outside a character class, in the default matching mode, the circumflex character is an assertion which is true only if the current matching point is at the start of the subject string. Inside a character class, circumflex has an entirely different meaning (see below).
Circumflex need not be the first character of the pattern if a number of alternatives are involved, but it should be the first thing in each alternative in which it appears if the pattern is ever to match that branch. If all possible alternatives start with a circumflex, that is, if the pattern is constrained to match only at the start of the subject, it is said to be an "anchored" pattern. (There are also other constructs that can cause a pattern to be anchored.)
A dollar character is an assertion which is true only if the current matching point is at the end of the subject string, or immediately before a newline character that is the last character in the string (by default). Dollar need not be the last character of the pattern if a number of alternatives are involved, but it should be the last item in any branch in which it appears. Dollar has no special meaning in a character class.
The meanings of the circumflex and dollar characters are changed if
the multiline option is set. When this is the case, they match
immediately after and immediately before an internal newline
character, respectively, in addition to matching at the start and end
of the subject string. For example, the pattern ^abc$
matches the
subject string "defnabc"
in multiline mode, but not otherwise.
Note that the sequences A
, Z
, and z
can be used to match the
start and end of the subject in both modes, and if all branches of a
pattern start with A
it is always anchored, whether
multiline is set or not.
5.3. Full Stop (period, dot)
Outside a character class, a dot in the pattern matches any one character in the subject, including a non-printing character, but not (by default) newline. If the dotall option is set, dots match newlines as well. The handling of dot is entirely independent of the handling of circumflex and dollar, the only relationship being that they both involve newline characters. Dot has no special meaning in a character class.
5.4. Square Brackets
An opening square bracket introduces a character class, terminated by a closing square bracket. A closing square bracket on its own is not special. If a closing square bracket is required as a member of the class, it should be the first data character in the class (after an initial circumflex, if present) or escaped with a backslash.
A character class matches a single character in the subject. A matched character must be in the set of characters defined by the class, unless the first character in the class definition is a circumflex, in which case the subject character must not be in the set defined by the class. If a circumflex is actually required as a member of the class, ensure it is not the first character, or escape it with a backslash.
For example, the character class [aeiou]
matches any lower case
vowel, while [^aeiou]
matches any character that is not a lower case
vowel. Note that a circumflex is just a convenient notation for
specifying the characters which are in the class by enumerating those
that are not. It is not an assertion: it still consumes a character
from the subject string, and fails if the current pointer is at the
end of the string.
When caseless matching is set, any letters in a class represent both
their upper case and lower case versions, so for example, a caseless
[aeiou]
matches "A" as well as "a", and a caseless [^aeiou]
does not match "A", whereas a caseful version would.
The newline character is never treated in any special way in character classes,
whatever the setting of the dotall or multiline options is. A class
such as [^a]
will always match a newline.
The minus (hyphen) character can be used to specify a range of characters in a character class. For example, [d-m] matches any letter between d and m, inclusive. If a minus character is required in a class, it must be escaped with a backslash or appear in a position where it cannot be interpreted as indicating a range, typically as the first or last character in the class.
It is not possible to have the literal character "]" as the end
character of a range. A pattern such as [W-]46]
is interpreted as a
class of two characters ("W" and "-") followed by a literal string
"46]", so it would match "W46]" or "-46]". However, if the "]" is
escaped with a backslash it is interpreted as the end of range, so
(W]46)
is interpreted as a single class containing a range followed
by two separate characters. The octal or hexadecimal representation of
"]" can also be used to end a range.
Ranges operate in the collating sequence of character values. They can also be
used for characters specified numerically, for example [000-037]
.
If a range that includes letters is used when caseless matching is set, it
matches the letters in either case. For example, [W-c]
is equivalent to
[][^_`wxyzabc]
, matched caselessly, and if character tables for the "fr"
locale are in use, [xc8-xcb]
matches accented E characters in both cases.
The character types d
, D
, s
, S
, 'w`, and W
may also appear in a
character class, and add the characters that they match to the class. For
example, [dABCDEF]
matches any hexadecimal digit. A circumflex can
conveniently be used with the upper case character types to specify a more
restricted set of characters than the matching lower case type. For example,
the class [^W_]
matches any letter or digit, but not underscore.
All non-alphameric characters other than `, `-
, ^
(at the start) and the
terminating ]
are non-special in character classes, but it does no harm if they
are escaped.
5.5. POSIX character classes
Perl supports the POSIX notation for character classes, which uses names enclosed by [: and :] within the enclosing square brackets. STklos , thanks to PCRE, also supports this notation. For example,
[01[:alpha:]%]
matches "0", "1", any alphabetic character, or "%". The supported class names are
alnum |
letters and digits |
alpha |
letters |
ascii |
character codes 0 - 127 |
blank |
space or tab only |
cntrl |
control characters |
digit |
decimal digits (same as d |
graph |
printing characters, excluding space |
lower |
lower case letters |
printing characters, including space |
|
punct |
printing characters, excluding letters and digits |
space |
white space (not quite the same as s) |
upper |
upper case letters |
word" |
word characters (same as w) |
xdigit |
hexadecimal digits |
The space characters are HT (9), LF (10), VT (11), FF (12), CR (13), and space (32). Notice that this list includes the VT character (code 11). This makes "space" different to $backslash$s, which does not include VT (for Perl compatibility).
The name word is a Perl extension, and blank is a GNU extension from Perl
5.8. Another Perl extension is negation, which is indicated by a ^
character
after the colon. For example,
[12[:^digit:]]
matches "1", "2", or any non-digit. STklos (and Perl) also
recognize the POSIX syntax [.ch.]
and [=ch=]
where "ch" is a
"collating element", but these are not supported, and an error is
given if they are encountered.
5.6. Vertical Bar
Vertical bar characters are used to separate alternative patterns. For example, the pattern
gilbert|sullivan
matches either "gilbert" or "sullivan". Any number of alternatives may appear, and an empty alternative is permitted (matching the empty string). The matching process tries each alternative in turn, from left to right, and the first one that succeeds is used. If the alternatives are within a subpattern (defined below), "succeeds" means matching the rest of the main pattern as well as the alternative in the subpattern.
5.7. Internal Option Setting
The settings of the caseless, multiline, dotall, and EXTENDED options can be changed from within the pattern by a sequence of Perl option letters enclosed between "(?" and ")". The option letters are
i |
for caseless |
m |
for multiline |
s |
for dotall |
x |
for extended |
For example, (?im)
sets caseless, multiline matching. It is also possible to
unset these options by preceding the letter with a hyphen, and a combined
setting and unsetting such as (?im-sx)
, which sets caseless and
multiline while unsetting dotall and extended, is also
permitted. If a letter appears both before and after the hyphen, the option is
unset.
When an option change occurs at top level (that is, not inside subpattern parentheses), the change applies to the remainder of the pattern that follows. If the change is placed right at the start of a pattern, PCRE extracts it into the global options
An option change within a subpattern affects only that part of the current pattern that follows it, so
(a(?i)b)c
matches abc
and aBc
and no other strings (assuming caseless is
not used).By this means, options can be made to have different
settings in different parts of the pattern. Any changes made in one
alternative do carry on into subsequent branches within the same
subpattern. For example,
(a(?i)b|c)
matches "ab", "aB", "c", and "C", even though when matching "C" the first branch is abandoned before the option setting. This is because the effects of option settings happen at compile time. There would be some very weird behaviour otherwise.
The PCRE-specific options ungreedy and extra can be changed in
the same way as the Perl-compatible options by using the characters
U
and X
respectively. The (?X)
flag setting is special in that
it must always occur earlier in the pattern than any of the additional
features it turns on, even when it is at top level. It is best put at
the start.
5.8. Subpatterns
Subpatterns are delimited by parentheses (round brackets), which can be nested. Marking part of a pattern as a subpattern does two things:
-
It localizes a set of alternatives. For example, the pattern
cat(aract|erpillar|)
matches one of the words "cat", "cataract", or "caterpillar". Without the parentheses, it would match "cataract", "erpillar" or the empty string.
-
It sets up the subpattern as a capturing subpattern (as defined above). When the whole pattern matches, that portion of the subject string that matched the subpattern is set so that it can be used in the regexp-replace or regexp-replace-all functions. Opening parentheses are counted from left to right (starting from 1) to obtain the numbers of the capturing subpatterns.
For example, if the string "the red king" is matched against the pattern
the ((red|white) (king|queen))
the captured substrings are "red king", "red", and "king", and are numbered 1, 2, and 3, respectively.
The fact that plain parentheses fulfil two functions is not always helpful. There are often times when a grouping subpattern is required without a capturing requirement. If an opening parenthesis is followed by a question mark and a colon, the subpattern does not do any capturing, and is not counted when computing the number of any subsequent capturing subpatterns. For example, if the string "the white queen" is matched against the pattern
the ((?:red|white) (king|queen))
the captured substrings are "white queen" and "queen", and are numbered 1 and 2. The maximum number of capturing subpatterns is 65535, and the maximum depth of nesting of all subpatterns, both capturing and non-capturing, is 200.
As a convenient shorthand, if any option settings are required at the
start of a non-capturing subpattern, the option letters may appear
between the "?" and the ":".
Thus the two patterns
(?i:saturday|sunday)
and
(?:(?i)saturday|sunday)
match exactly the same set of strings. Because alternative branches are tried from left to right, and options are not reset until the end of the subpattern is reached, an option setting in one branch does affect subsequent branches, so the above patterns match "SUNDAY" as well as "Saturday".
5.9. Named Subpatterns
Identifying capturing parentheses by number is simple, but it can be very hard to keep track of the numbers in complicated regular expressions. Furthermore, if an expression is modified, the numbers may change. To help with the difficulty, PCRE supports the naming of subpatterns, something that Perl does not provide. The Python syntax (?P<name>…) is used. Names consist of alphanumeric characters and underscores, and must be unique within a pattern.
5.10. Repetition
Repetition is specified by quantifiers, which can follow any of the following items:
-
a literal data character
-
the
.
metacharacter -
the
C
escape sequence -
escapes such as
d
that match single characters -
a character class
-
a back reference (see next section)
-
a parenthesized subpattern (unless it is an assertion)
The general repetition quantifier specifies a minimum and maximum number of permitted matches, by giving the two numbers in curly brackets (braces), separated by a comma. The numbers must be less than 65536, and the first must be less than or equal to the second. For example:
z{2,4}
matches "zz", "zzz", or "zzzz". A closing brace on its own is not a special character. If the second number is omitted, but the comma is present, there is no upper limit; if the second number and the comma are both omitted, the quantifier specifies an exact number of required matches. Thus
[aeiou]{3,}
matches at least 3 successive vowels, but may match many more, while
d{8}
matches exactly 8 digits. An opening curly bracket that appears in a position where a quantifier is not allowed, or one that does not match the syntax of a quantifier, is taken as a literal character. For example, {,6} is not a quantifier, but a literal string of four characters.
The quantifier {0} is permitted, causing the expression to behave as if the previous item and the quantifier were not present.
For convenience (and historical compatibility) the three most common quantifiers have single-character abbreviations:
-
*
is equivalent to {0,} -
+
is equivalent to {1,} -
?
is equivalent to {0,1}
It is possible to construct infinite loops by following a subpattern that can match no characters with a quantifier that has no upper limit, for example:
(a?)*
Earlier versions of Perl and PCRE used to give an error at compile time for such patterns. However, because there are cases where this can be useful, such patterns are now accepted, but if any repetition of the subpattern does in fact match no characters, the loop is forcibly broken.
By default, the quantifiers are "greedy", that is, they match as much as
possible (up to the maximum number of permitted times), without causing the
rest of the pattern to fail. The classic example of where this gives problems
is in trying to match comments in C programs. These appear between the
sequences /
and /
and within the sequence, individual *
and /
characters may
appear. An attempt to match C comments by applying the pattern
/*.**/
to the string
/* first command */ not comment /* second comment */
fails, because it matches the entire string owing to the greediness of the .*
item.
However, if a quantifier is followed by a question mark, it ceases to be greedy, and instead matches the minimum number of times possible, so the pattern
/*.*?*/
does the right thing with the C comments. The meaning of the various quantifiers is not otherwise changed, just the preferred number of matches. Do not confuse this use of question mark with its use as a quantifier in its own right. Because it has two uses, it can sometimes appear doubled, as in
d??d
which matches one digit by preference, but can match two if that is the only way the rest of the pattern matches.
If the ungreedy option is set (an option which is not available in Perl), the quantifiers are not greedy by default, but individual ones can be made greedy by following them with a question mark. In other words, it inverts the default behaviour.
When a parenthesized subpattern is quantified with a minimum repeat count that is greater than 1 or with a limited maximum, more store is required for the compiled pattern, in proportion to the size of the minimum or maximum.
If a pattern starts with .*
or .{0,}
and the dotall option (equivalent
to Perl’s /s
) is set, thus allowing the .
to match newlines, the pattern is
implicitly anchored, because whatever follows will be tried against every
character position in the subject string, so there is no point in retrying the
overall match at any position after the first. PCRE normally treats such a
pattern as though it were preceded by A
.
In cases where it is known that the subject string contains no newlines, it is
worth setting dotall in order to obtain this optimization, or
alternatively using ^
to indicate anchoring explicitly.
However, there is one situation where the optimization cannot be used. When .*
is inside capturing parentheses that are the subject of a backreference
elsewhere in the pattern, a match at the start may fail, and a later one
succeed. Consider, for example:
(.*)abc1
If the subject is "xyz123abc123"
the match point is the fourth character. For
this reason, such a pattern is not implicitly anchored.
When a capturing subpattern is repeated, the value captured is the substring that matched the final iteration. For example, after
(tweedle[dume]{3}s*)+
has matched "tweedledum tweedledee" the value of the captured substring is "tweedledee". However, if there are nested capturing subpatterns, the corresponding captured values may have been set in previous iterations. For example, after
(a|(b))+
5.11. Atomic Grouping And Possessive Quantifiers
With both maximizing and minimizing repetition, failure of what follows normally causes the repeated item to be re-evaluated to see if a different number of repeats allows the rest of the pattern to match. Sometimes it is useful to prevent this, either to change the nature of the match, or to cause it fail earlier than it otherwise might, when the author of the pattern knows there is no point in carrying on.
Consider, for example, the pattern d+foo
when applied to the subject line
123456bar
After matching all 6 digits and then failing to match "foo", the normal
action of the matcher is to try again with only 5 digits matching the d+
item, and then with 4, and so on, before ultimately failing. "Atomic grouping"
(a term taken from Jeffrey Friedl’s book) provides the means for specifying
that once a subpattern has matched, it is not to be re-evaluated in this way.
If we use atomic grouping for the previous example, the matcher would give up
immediately on failing to match "foo" the first time. The notation is a kind of
special parenthesis, starting with (?>
as in this example:)
(?>d+)foo
This kind of parenthesis "locks up" the part of the pattern it contains once it has matched, and a failure further into the pattern is prevented from backtracking into it. Backtracking past it to previous items, however, works as normal.
An alternative description is that a subpattern of this type matches the string of characters that an identical standalone pattern would match, if anchored at the current point in the subject string.
Atomic grouping subpatterns are not capturing subpatterns. Simple
cases such as the above example can be thought of as a maximizing
repeat that must swallow everything it can. So, while both
d+
and d+?
are prepared to adjust the number
of digits they match in order to make the rest of the pattern match,
(?>d+)
can only match an entire sequence of digits.
Atomic groups in general can of course contain arbitrarily complicated
subpatterns, and can be nested. However, when the subpattern for an atomic
group is just a single repeated item, as in the example above, a simpler
notation, called a "possessive quantifier" can be used. This consists of an
additional +
character following a quantifier. Using this notation, the
previous example can be rewritten as
d++bar
Possessive quantifiers are always greedy; the setting of the ungreedy option is ignored. They are a convenient notation for the simpler forms of atomic group. However, there is no difference in the meaning or processing of a possessive quantifier and the equivalent atomic group.
The possessive quantifier syntax is an extension to the Perl syntax. It originates in Sun’s Java package.
When a pattern contains an unlimited repeat inside a subpattern that can itself be repeated an unlimited number of times, the use of an atomic group is the only way to avoid some failing matches taking a very long time indeed. The pattern
(D+|<d+>)*[!?]
matches an unlimited number of substrings that either consist of non-digits, or digits enclosed in <>, followed by either ! or ?. When it matches, it runs quickly. However, if it is applied to
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
it takes a long time before reporting failure. This is because the string can
be divided between the two repeats in a large number of ways, and all have to
be tried. (The example used [!?]
rather than a single character at the end,
because both PCRE and Perl have an optimization that allows for fast failure
when a single character is used. They remember the last single character that
is required for a match, and fail early if it is not present in the string.)
If the pattern is changed to
((?>D+)|<d+>)*[!?]
sequences of non-digits cannot be broken, and failure happens quickly.
5.12. Back References
Outside a character class, a backslash followed by a digit greater than 0 (and possibly further digits) is a back reference to a capturing subpattern earlier (that is, to its left) in the pattern, provided there have been that many previous capturing left parentheses.
However, if the decimal number following the backslash is less than 10, it is always taken as a back reference, and causes an error only if there are not that many capturing left parentheses in the entire pattern. In other words, the parentheses that are referenced need not be to the left of the reference for numbers less than 10. See the section entitled "Backslash" above for further details of the handling of digits following a backslash.
A back reference matches whatever actually matched the capturing subpattern in the current subject string, rather than anything matching the subpattern itself (see below for a way of doing that). So the pattern
(sens|respons)e and 1ibility
matches "sense and sensibility" and "response and responsibility", but not "sense and responsibility". If caseful matching is in force at the time of the back reference, the case of letters is relevant. For example,
((?i)rah)s+1
matches "rah rah" and "RAH RAH", but not "RAH rah", even though the original capturing subpattern is matched caselessly.
Back references to named subpatterns use the Python syntax (?P=name)
. We could
rewrite the above example as follows:
(?<p1>(?i)rah)s+(?P=p1)
There may be more than one back reference to the same subpattern. If a subpattern has not actually been used in a particular match, any back references to it always fail. For example, the pattern
(a|(bc))2
always fails if it starts to match "a" rather than "bc". Because there may be many capturing parentheses in a pattern, all digits following the backslash are taken as part of a potential back reference number. If the pattern continues with a digit character, some delimiter must be used to terminate the back reference. If the extended option is set, this can be whitespace. Otherwise an empty comment can be used.
A back reference that occurs inside the parentheses to which it refers fails when the subpattern is first used, so, for example, (a1) never matches. However, such references can be useful inside repeated subpatterns. For example, the pattern
(a|b1)+
matches any number of "a"s and also "aba", "ababbaa" etc. At each iteration of the subpattern, the back reference matches the character string corresponding to the previous iteration. In order for this to work, the pattern must be such that the first iteration does not need to match the back reference. This can be done using alternation, as in the example above, or by a quantifier with a minimum of zero.
5.13. Assertions
An assertion is a test on the characters following or preceding the current
matching point that does not actually consume any characters. The simple
assertions coded as b
, B
, A
, G
, Z
, z
, ^
and $
are described above.
More complicated assertions are coded as subpatterns. There are two kinds:
those that look ahead of the current position in the subject string, and those
that look behind it.
An assertion subpattern is matched in the normal way, except that it does not
cause the current matching position to be changed. Lookahead assertions start
with (?=
for positive assertions and (?!
for negative assertions. For example,
w+(?=;)
matches a word followed by a semicolon, but does not include the semicolon in the match, and
foo(?!bar)
matches any occurrence of "foo" that is not followed by "bar". Note that the apparently similar pattern
(?!foo)bar
does not find an occurrence of "bar" that is preceded by something other than
"foo"; it finds any occurrence of "bar" whatsoever, because the assertion
(?!foo)
is always true when the next three characters are "bar". A
lookbehind assertion is needed to achieve this effect.
If you want to force a matching failure at some point in a pattern, the most
convenient way to do it is with (?!)
because an empty string always matches, so
an assertion that requires there not to be an empty string must always fail.
Lookbehind assertions start with (?⇐
for positive assertions and (?<!
for
negative assertions. For example,
(?<!foo)bar
does find an occurrence of "bar" that is not preceded by "foo". The contents of a lookbehind assertion are restricted such that all the strings it matches must have a fixed length. However, if there are several alternatives, they do not all have to have the same fixed length. Thus
(?<=bullock|donkey)
is permitted, but
(?<!dogs?|cats?)
causes an error at compile time. Branches that match different length strings are permitted only at the top level of a lookbehind assertion. This is an extension compared with Perl (at least for 5.8), which requires all branches to match the same length of string. An assertion such as
(?<=ab(c|de))
is not permitted, because its single top-level branch can match two different lengths, but it is acceptable if rewritten to use two top-level branches:
(?<=abc|abde)
The implementation of lookbehind assertions is, for each alternative, to temporarily move the current position back by the fixed width and then try to match. If there are insufficient characters before the current position, the match is deemed to fail.
Atomic groups can be used in conjunction with lookbehind assertions to specify efficient matching at the end of the subject string. Consider a simple pattern such as
abcd$
when applied to a long string that does not match. Because matching proceeds from left to right, PCRE will look for each "a" in the subject and then see if what follows matches the rest of the pattern. If the pattern is specified as
^.*abcd$
the initial .* matches the entire string at first, but when this fails (because there is no following "a"), it backtracks to match all but the last character, then all but the last two characters, and so on. Once again the search for "a" covers the entire string, from right to left, so we are no better off. However, if the pattern is written as
^(?>.*)(?<=abcd)
or, equivalently,
^.*+(?<=abcd)
there can be no backtracking for the .*
item; it can match only the entire
string. The subsequent lookbehind assertion does a single test on the last four
characters. If it fails, the match fails immediately. For long strings, this
approach makes a significant difference to the processing time.
Several assertions (of any sort) may occur in succession. For example,
(?<=d{3})(?<!999)foo
matches "foo" preceded by three digits that are not "999". Notice that each of the assertions is applied independently at the same point in the subject string. First there is a check that the previous three characters are all digits, and then there is a check that the same three characters are not "999". This pattern does fInotfR match "foo" preceded by six characters, the first of which are digits and the last three of which are not "999". For example, it doesn’t match "123abcfoo". A pattern to do that is
(?<=d{3}...)(?<!999)foo
This time the first assertion looks at the preceding six characters, checking that the first three are digits, and then the second assertion checks that the preceding three characters are not "999".
Assertions can be nested in any combination. For example,
(?<=(?<!foo)bar)baz
matches an occurrence of "baz" that is preceded by "bar" which in turn is not preceded by "foo", while
(?<=d{3}(?!999)...)foo
is another pattern which matches "foo" preceded by three digits and any three characters that are not "999".
Assertion subpatterns are not capturing subpatterns, and may not be repeated, because it makes no sense to assert the same thing several times. If any kind of assertion contains capturing subpatterns within it, these are counted for the purposes of numbering the capturing subpatterns in the whole pattern. However, substring capturing is carried out only for positive assertions, because it does not make sense for negative assertions.
5.14. Conditional Subpatterns
It is possible to cause the matching process to obey a subpattern conditionally or to choose between two alternative subpatterns, depending on the result of an assertion, or whether a previous capturing subpattern matched or not. The two possible forms of conditional subpattern are
(?(condition)yes-pattern)
(?(condition)yes-pattern|no-pattern)
If the condition is satisfied, the yes-pattern is used; otherwise the no-pattern (if present) is used. If there are more than two alternatives in the subpattern, a compile-time error occurs.
There are three kinds of condition. If the text between the parentheses consists of a sequence of digits, the condition is satisfied if the capturing subpattern of that number has previously matched. The number must be greater than zero. Consider the following pattern, which contains non-significant white space to make it more readable (assume the extended option) and to divide it into three parts for ease of discussion:
( ( )? [^()]+ (?(1) ) )
The first part matches an optional opening parenthesis, and if that character is present, sets it as the first captured substring. The second part matches one or more characters that are not parentheses. The third part is a conditional subpattern that tests whether the first set of parentheses matched or not. If they did, that is, if subject started with an opening parenthesis, the condition is true, and so the yes-pattern is executed and a closing parenthesis is required. Otherwise, since no-pattern is not present, the subpattern matches nothing. In other words, this pattern matches a sequence of non-parentheses, optionally enclosed in parentheses.
If the condition is the string ®
, it is satisfied if a recursive call to the
pattern or subpattern has been made. At "top level", the condition is false.
This is a PCRE extension. See PCRE documentation for recursive patterns.
If the condition is not a sequence of digits or ®
, it must be an assertion.
This may be a positive or negative lookahead or lookbehind assertion. Consider
this pattern, again containing non-significant white space, and with the two
alternatives on the second line:
(?(?=`(^a-z)*`(a-z))
d{2}-`(a-z){3}-d{2} | d{2}-d{2}-d{2} )
The condition is a positive lookahead assertion that matches an optional sequence of non-letters followed by a letter. In other words, it tests for the presence of at least one letter in the subject. If a letter is found, the subject is matched against the first alternative; otherwise it is matched against the second. This pattern matches strings in one of the two forms dd-aaa-dd or dd-dd-dd, where aaa are letters and dd are digits.
5.15. Comments
The sequence (?#
marks the start of a comment which continues up to the next
closing parenthesis. Nested parentheses are not permitted. The characters
that make up a comment play no part in the pattern matching at all.
If the extended option is set, an unescaped #
character outside a
character class introduces a comment that continues up to the next newline
character in the pattern.
5.16. Subpatterns As Subroutines
If the syntax for a recursive subpattern reference (either by number or by name) is used outside the parentheses to which it refers, it operates like a subroutine in a programming language. An earlier example pointed out that the pattern
(sens|respons)e and 1ibility
matches "sense and sensibility" and "response and responsibility", but not "sense and responsibility". If instead the pattern
(sens|respons)e and (?1)ibility
is used, it does match "sense and responsibility" as well as the other two strings. Such references must, however, follow the subpattern to which they refer.
5.17. Regexp Procedures
This section lists the STklos functions that can use PCRE regexpr described before
STklos procedure
String→regexp
takes a string representation of a regular
expression and compiles it into a regexp value. Other regular
expression procedures accept either a string or a regexp value as
the matching pattern. If a regular expression string is used
multiple times, it is faster to compile the string once to a regexp
value and use it for repeated matches instead of using the string
each time.
STklos procedure
Regexp
returns #t
if obj
is a regexp value created by the regexp
,
otherwise regexp
returns #f
.
STklos procedure
These functions attempt to match pattern
(a string or a regexp value)
to str
. If the match fails, #f
is returned. If the match succeeds,
a list (containing strings for regexp-match
and positions for
regexp-match-positions
) is returned. The first string (or positions) in
this list is the portion of string that matched pattern. If two portions
of string can match pattern, then the earliest and longest match is found,
by default.
Additional strings or positions are returned in the list if pattern contains parenthesized sub-expressions; matches for the sub-expressions are provided in the order of the opening parentheses in pattern.
(regexp-match-positions "ca" "abracadabra")
=> ((4 6))
(regexp-match-positions "CA" "abracadabra")
=> #f
(regexp-match-positions "(?i)CA" "abracadabra")
=> ((4 6))
(regexp-match "(a*)(b*)(c*)" "abc")
=> ("abc" "a" "b" "c")
(regexp-match-positions "(a*)(b*)(c*)" "abc")
=> ((0 3) (0 1) (1 2) (2 3))
(regexp-match-positions "(a*)(b*)(c*)" "c")
=> ((0 1) (0 0) (0 0) (0 1))
(regexp-match-positions "(?<=\d{3})(?<!999)foo"
"999foo and 123foo")
=> ((14 17))
STklos procedure
Regexp-replace
matches the regular expression pattern
against
string
. If there is a match, the portion of string
which matches
pattern
is replaced by the substitution
string. If there is no
match, regexp-replace
returns string
unmodified. Note that the
given pattern
could be here either a string or a regular expression.
If pattern
contains n
where n is a digit between 1 and 9,
then it is replaced in the substitution with the portion of string that
matched the n-th parenthesized subexpression of pattern
. If
n is equal to 0, then it is replaced in substitution
with the portion of string
that matched pattern
.
Regexp-replace
replaces the first occurrence of pattern
in string
.
To replace all the occurrences of pattern
, use regexp-replace-all
.
(regexp-replace "a*b" "aaabbcccc" "X")
=> "Xbcccc"
(regexp-replace (string->regexp "a*b") "aaabbcccc" "X")
=> "Xbcccc"
(regexp-replace "(a*)b" "aaabbcccc" "X\1Y")
=> "XaaaYbcccc"
(regexp-replace "f(.*)r" "foobar" "\1 \1")
=> "ooba ooba"
(regexp-replace "f(.*)r" "foobar" "\0 \0")
=> "foobar foobar"
(regexp-replace "a*b" "aaabbcccc" "X")
=> "Xbcccc"
(regexp-replace-all "a*b" "aaabbcccc" "X")
=> "XXcccc"
STklos procedure
Takes an arbitrary string and returns a string where characters of
str
that could serve as regexp metacharacters are escaped with a
backslash, so that they safely match only themselves.
(regexp-quote "cons") => "cons"
(regexp-quote "list?") => "list\?"
regexp-quote
is useful when building a composite regexp from
a mix of regexp strings and verbatim strings.
6. Pattern Matching
Pattern matching is a key feature of most modern functional programming languages since it allows clean and secure code to be written. Internally, "pattern-matching forms" should be translated (compiled) into cascades of "elementary tests" where code is made as efficient as possible, avoiding redundant tests; STklos "pattern matching compiler" provides this [6]. The code (and documentation) included in STklos has been stolen from the Bigloo package v4.5 (the only difference between both package is the pattern matching of structures which is absent in STklos.
The technique used is described in details in C. Queinnec and J-M. Geffroy paper [QuG92], and the code generated can be considered optimal
The "pattern language" allows the expression of a wide variety of patterns, including:
-
Non-linear patterns: pattern variables can appear more than once, allowing comparison of subparts of the datum (through
eq?
) -
Recursive patterns on lists: for example, checking that the datum is a list of zero or more
a
s followed by zero or more`b
s. -
Pattern matching on lists as well as on vectors.
6.1. The Pattern Language
The syntax for <pattern>
is:
[:small]
<pattern> | Matches: |
---|---|
<atom> |
the <atom>. |
(kwote <atom>) |
any expression eq? to <atom>. |
(and <pat1> … <patn>) |
if all of <pati> match. |
(or <pat1> … …<patn>) |
if any of <pat1> through <patn> matches. |
(not <pat>) |
if <pat> doesn’t match. |
(? <predicate>) |
if <predicate> is true. |
(<pat1> … <patn>) |
a list of n elements. Here, … is a meta-character denoting a finite repetition of patterns. |
<pat> … |
a (possibly empty) repetition of <pat> in a list. |
#(<pat> … <patn>) |
a vector of n elements. |
?<id> |
anything, and binds id as a variable. |
?- |
anything. |
??- |
any (possibly empty) repetition of anything in a list. |
???- |
any end of list. |
Remark: and
, or
, not
and kwote
must be quoted in order to be treated
as literals. This is the only justification for having the kwote
pattern
since, by convention, any atom which is not a keyword is quoted.
Explanations Through Examples
-
?-
matches any s-expr. -
a
matches the atom'a
. -
?a
matches any expression, and binds the variablea
to this expression. -
(? integer?)
matches any integer. -
(a (a b))
matches the only list'(a (a b))
. -
???-
can only appear at the end of a list, and always succeeds. For instance,(a ???-)
is equivalent to(a . ?-)
. -
when occurring in a list,
??-
matches any sequence of anything:(a ??- b)
matches any list whosecar
isa
and lastcar
isb
. -
(a …)
matches any list of `a’s, possibly empty. -
(?x ?x)
matches any list of length 2 whosecar
is eq to itscadr
. -
((and (not a) ?x) ?x)
matches any list of length 2 whosecar
is not eq to'a
but is eq to itscadr
. -
#(?- ?- ???-)
matches any vector whose length is at least 2.
??- and … patterns can not appear inside a vector, where you
should use ???- For example, #(a ??- b) or #(a…) are invalid
patterns, whereas #(a ???-) is valid and matches any vector whose first
element is the atom a .
|
6.2. STklos Pattern Matching Facilities
Only two special forms are provided for this in STklos: match-case
and
match-lambda
.
STklos syntax
The argument key may be any expression and each clause has the form
(<pattern> <expression> ...)
A match-case expression is evaluated as follows: <key>
is evaluated
and the result is compared with each successive pattern. If the <pattern>
in some clause yields a match, then the <expression>
s in that clause are
evaluated from left to right in an environment where the pattern variables
are bound to the corresponding subparts of <key>
, and the result of the
last expression in that clause is returned as the result of the
match-case
expression. If no pattern in any clause matches the <key>
,
then, if there is an else
clause, its expressions are evaluated and
the result of the last is the result of the whole match-case
expression; otherwise the result of the match-case
expression
is unspecified.
The equality predicate used for tests is eq?
.
(match-case '(a b a)
((?x ?x) 'foo)
((?x ?- ?x) 'bar)) => bar
(match-case '(a (b c) d)
((?x ?y) (list 'length=2 y x))
((?x ?y ?z) (list 'length=3 z y x)))
=> (length=3 d (b c) a)
STklos syntax
match-lambda
expands into a lambda-expression expecting an argument
which, once applied to an expression, behaves exactly like a
match-case
expression.
((match-lambda
((?x ?x) 'foo)
((?x ?- ?x) 'bar))
'(a b a)) => bar
7. Exceptions and Conditions
7.1. Exceptions
The following text is extracted from SRFI-34 (Exception Handling for Programs), from which STklos exceptions are derived. Note that exceptions are now part of R7RS.
Exception handlers are one-argument procedures that determine the action the program takes when an exceptional situation is signalled. The system implicitly maintains a current exception handler.
The program raises an exception by invoking the current exception handler, passing to it an object encapsulating information about the exception. Any procedure accepting one argument may serve as an exception handler and any object may be used to represent an exception.
The system maintains the current exception handler as part of the dynamic environment of the program, akin to the current input or output port, or the context for dynamic-wind. The dynamic environment can be thought of as that part of a continuation that does not specify the destination of any returned values. It includes the current input and output ports, the dynamic-wind context, and this SRFI’s current exception handler.
STklos syntax
Evaluates the sequences of expressions <expr1>
to <exprn>
.
<handler>
must be a procedure that accepts one argument. It is installed
as the current exception handler for the dynamic extent (as determined by
dynamic-wind) of the evaluations of the expressions
(with-handler (lambda (c)
(display "Catch an error\n"))
(display "One ... ")
(+ "will yield" "an error")
(display "... Two"))
|- "One ... Catch an error"
R7RS procedure
This form is similar to with-handler
. It uses a thunk instead of
a sequence of expressions. It is conform to SRFI-34 (Exception Handling for Programs).
In fact,
(with-handler <handler> <expr1> ... <exprn>)
is equivalent to
(with-exception-handler <handler>
(lambda () <expr1> ... <exprn>))
R7RS procedure
Invokes the current exception handler on obj
. The handler is called in
the dynamic environment of the call to raise
, except that the current
exception handler is that in place for the call to with-handler
that installed the handler being called.
(with-handler (lambda (c)
(format "value ~A was raised" c))
(raise 'foo)
(format #t "never printed\n"))
=> "value foo was raised"
R7RS procedure
Raises an exception by invoking the current exception handler on
obj
. The handler is called with the same dynamic environment as the
call to raise-continuable
, except that: (1) the current exception
handler is the one that was in place when the handler being called was
installed, and (2) if the handler being called returns, then it will again
become the current exception handler. If the handler returns, the values
it returns become the values returned by the call to raise-continuable
.
(with-exception-handler
(lambda (con)
(cond
((string? con)
(display con))
(else
(display "a warning has been issued")))
42)
(lambda ()
(+ (raise-continuable "should be a number")
23)))
;; prints should be a number
=> 65
R7RS procedure
Evaluating a guard form evaluates <body>
with an exception handler
that binds the raised object to <var>
and within the scope of that
binding evaluates the clauses as if they were the clauses of a cond
expression. That implicit cond expression is evaluated with the
continuation and dynamic environment of the guard
expression.
If every <clause>
s test evaluates to false and there is no else
clause, then raise
is re-invoked on the raised object within the
dynamic environment of the original call to raise
except that the
current exception handler is that of the guard
expression.
(guard (condition
((assq 'a condition) => cdr)
((assq 'b condition)))
(raise (list (cons 'a 42))))
=> 42
(guard (condition
((assq 'a condition) => cdr)
((assq 'b condition)))
(raise (list (cons 'b 23))))
=> (b . 23)
(with-handler (lambda (c) (format "value ~A was raised" c))
(