Kernel is a language in the LISP/Scheme family. This implementation, while faithful to the novel semantics of Kernel and consistent with John's specification, is not a conforming Kernel because it does not provide all of the required features defined in the Kernel standard (R-1RK). However, we believe it is a useful subset which illustrates our own novel actor-based approach to the implementation. This implementation is designed for machines with 32-bit words.
(exit)
The exit
applicative terminates the Kernel runtime system.
(boolean? .
objects)
The boolean?
applicative returns #t
if objects all have boolean type,
otherwise #f
.
(symbol? .
objects)
The symbol?
applicative returns #t
if objects all have symbol type,
otherwise #f
.
(inert? .
objects)
The inert?
applicative returns #t
if objects are all #inert
,
otherwise #f
.
(pair? .
objects)
The pair?
applicative returns #t
if objects all have pair type,
otherwise #f
.
(null? .
objects)
The null?
applicative returns #t
if objects are all ()
,
otherwise #f
.
(operative? .
objects)
The operative?
applicative returns #t
if objects all have operative type,
otherwise #f
.
(applicative? .
objects)
The applicative?
applicative returns #t
if objects all have applicative type,
otherwise #f
.
(combiner? .
objects)
The combiner?
applicative returns #t
if objects all either operative or applicative type,
otherwise #f
.
(ignore? .
objects)
The ignore?
applicative returns #t
if objects are all #ignore
,
otherwise #f
.
(environment? .
objects)
The environment?
applicative returns #t
if objects all have environment type,
otherwise #f
.
(eq? .
objects)
The eq?
applicative returns #t
unless some two of its arguments
are different objects,
otherwise #f
.
For any particular two objects,
the result returned by eq?
is always the same.
(equal? .
objects)
The equal?
applicative returns #t
unless some two of its arguments
have different values,
otherwise #f
.
For any particular two objects,
the result returned by eq?
may change
if one of them is mutated.
($if
⟨test⟩
⟨consequent⟩
⟨alternative⟩)
The $if
operative first evaluates ⟨test⟩ in the dynamic environment.
If the result is not of type boolean, an error is signaled.
If the result is #t
, ⟨consequent⟩ is then evaluated
in the dynamic environment as a tail context.
Otherwise, ⟨alternative⟩ is evaluated
in the dynamic environment as a tail context.
(cons
object1
object2)
A new pair object is constructed and returned,
whose car and cdr referents are respectively object1 and object2.
The objects returned by two different calls to cons
are not eq?
.
(list .
objects)
The list
applicative returns objects.
The underlying operative of list
returns its undifferentiated operand tree,
regardless of whether that tree is or is not a list.
The behavior of the applicative is therefore determined
by the way the Kernel evaluator algorithm evaluates arguments.
($define!
⟨definiend⟩
⟨expression⟩)
The $define!
operative evaluates ⟨expression⟩ in the dynamic environment
(that is, the environment in which the ($define! ...) combination is evaluated),
and matches ⟨definiend⟩ to the result in the dynamic environment,
binding each symbol in ⟨definiend⟩ in the dynamic environment
to the corresponding part of the result.
The result returned by $define!
is #inert
.
($vau
⟨formals⟩
⟨eformal⟩.
⟨objects⟩)
⟨formals⟩ should be a formal parameter tree,
as described for the ⟨definiend⟩ of the $define!
operative.
⟨eformal⟩ should be either a symbol or #ignore
.
A $vau
expression evaluates to an operative.
The environment in which the $vau
expression was evaluated
is remembered as the compound operative’s static environment.
When the compound operative is later called with an object and an environment,
here called respectively the operand tree and the dynamic environment,
- A new, initially empty local environment is created, with the static environment as its parent.
- The formal parameter tree ⟨formals⟩ is matched in the local environment to the operand tree, binding the symbols of ⟨formals⟩ to the corresponding parts of the operand tree.
- ⟨eformal⟩ is matched to the dynamic environment;
that is, if ⟨eformal⟩ is a symbol then that symbol is bound to the dynamic environment,
or ignored if ⟨eformal⟩ is
#ignore
. - The expressions in ⟨objects⟩ are evaluated sequentially,
from left to right, in the local environment.
The final expression is evaluated in a tail context.
If ⟨objects⟩ is
()
, the result is#inert
.
(wrap
combiner)
The wrap
applicative returns an applicative whose underlying combiner is combiner.
(unwrap
applicative)
The unwrap
applicative returns the underlying combiner of applicative.
If applicative is not an applicative, an error is signaled.
($sequence .
⟨objects⟩)
The $sequence
operative evaluates the elements of the list ⟨objects⟩
in the dynamic environment, one at a time from left to right.
If ⟨objects⟩ is a nonempty finite list,
its last element is evaluated as a tail context.
If ⟨objects⟩ is ()
, the result is #inert
.
($lambda
⟨formals⟩.
⟨objects⟩)
⟨formals⟩ should be a formal parameter tree as described for operative $define!
.
The expression
($lambda ⟨formals⟩ . ⟨objects⟩)
is equivalent to
(wrap ($vau ⟨formals⟩ #ignore . ⟨objects⟩))
(eval
expression
environment)
The eval
applicative evaluates expression
as a tail context in environment,
and returns the resulting value.
(make-env .
environments)
The make-env
applicative constructs and returns a new environment,
with initially no local bindings,
and an optional parent environment.
The current implementation supports integers only, using 32-bit signed 2's-complement representation.
(number? .
objects)
The number?
applicative returns #t
if objects all have number type,
otherwise #f
.
(=? .
numbers)
Applicative =?
is a predicate that returns #t
iff
all its arguments are numerically equal to each other.
(<? .
numbers)
(<=? .
numbers)
(>=? .
numbers)
(>? .
numbers)
Each of these applicatives is a predicate that returns #t
iff
the numerical values of every two consecutive elements
obey the order indicated by the name of the applicative.
(+ .
numbers)
Applicative +
returns the sum of the elements of numbers.
If numbers is empty, the sum of its elements is 0
.
(-
number.
numbers)
Applicative -
returns the sum of number with
the negation of the sum of numbers.
(* .
numbers)
Applicative *
returns the product of the elements of numbers.
If numbers is empty, the product of its elements is 1
.
In this implementation, numbers can be treated as 32-bit binary vectors.
(bit-not
number)
(bit-and .
numbers)
(bit-or .
numbers)
(bit-xor .
numbers)
(bit-lsl
number
amount)
(bit-lsr
number
amount)
(bit-asr
number
amount)
(car
pair)
($define! car
($lambda ((x . #ignore)) x))
(cdr
pair)
($define! cdr
($lambda ((#ignore . x)) x))
(caar
pair)
(cdar
pair)
(cadr
pair)
(cddr
pair)
(caddr
pair)
($define! caar
($lambda (((x . #ignore) . #ignore)) x))
($define! cdar
($lambda (((#ignore . x) . #ignore)) x))
($define! cadr
($lambda ((#ignore x . #ignore)) x))
($define! cddr
($lambda ((#ignore . (#ignore . x))) x))
($define! caddr
($lambda ((#ignore . (#ignore . (x . #ignore)))) x))
(get-current-env)
($define! get-current-env
(wrap ($vau () e e)))
(make-standard-env)
($define! make-standard-env
($lambda () (get-current-env)))
($binds?
⟨env⟩.
⟨symbols⟩)
not implemented
($get
⟨env⟩
⟨symbol⟩)
Operative $get
evaluates ⟨env⟩ in the dynamic environment.
The resulting env, must be an environment.
If ⟨symbol⟩ is not bound in env, an error is signaled.
If this is not desired, use $binds?
to check first.
($define! $get
($vau (env symbol) dyn
(eval symbol
(eval env dyn))))
($set!
⟨env⟩
⟨formal⟩
⟨value⟩)
Operative $set!
evaluates ⟨env⟩ and ⟨value⟩ in the dynamic environment.
The results are env (which must be an environment) and value.
Then ⟨formal⟩ is matched to value in the environment env.
The result returned by $set!
is #inert
.
($define! $set!
($vau (env formal value) dyn
(eval
(list $define! formal
(list (unwrap eval) value dyn))
(eval env dyn))))
(apply
applicative
object
environment)
(apply
applicative
object)
When the first syntax is used,
applicative apply
combines the underlying combiner of applicative
with object in dynamic environment environment, as a tail context.
The expression
(apply applicative object environment)
is equivalent to
(eval (cons (unwrap applicative) object) environment)
The second syntax is just syntactic sugar; the expression
(apply applicative object)
is equivalent to
(apply applicative object (make-env))
($define! apply
($lambda (appl arg . opt)
(eval
(cons (unwrap appl) arg)
($if (null? opt) (make-env) (car opt)))
))
(list*
object.
objects)
The expression
(list* (list 1 2) (list 3 4))
evaluates to
((1 2) 3 4)
($define! list*
($lambda (h . t)
($if (null? t)
h
(cons h (apply list* t)))
))
($cond .
⟨clauses⟩)
⟨clauses⟩ should be a list of clause expressions,
each of the form (
⟨test⟩.
⟨body⟩)
,
where ⟨body⟩ is a list of expressions.
The expression
($cond (⟨test⟩ . ⟨body⟩) . ⟨clauses⟩)
is equivalent to
($if ⟨test⟩ ($sequence . ⟨body⟩) ($cond . ⟨clauses⟩))
while the expression ($cond)
is equivalent to #inert
.
($define! $cond
($vau clauses env
($if (null? clauses)
#inert
(apply
($lambda ((test . body) . rest)
($if (eval test env)
(eval (cons $sequence body) env)
(eval (cons $cond rest) env)))
clauses))))
($provide!
⟨symbols⟩.
⟨body⟩)
The $provide!
operative constructs a child e of the dynamic environment d;
evaluates the elements of ⟨body⟩ in e, from left to right, discarding all of the results;
and exports all of the bindings of symbols in ⟨symbols⟩ from e to d,
i.e., binds each symbol in d to the result of looking it up in e.
The result returned by $provide!
is #inert
.
($define! $provide!
($vau (symbols . body) env
(eval
(list $define! symbols
(list
(list $lambda ()
(list* $sequence body)
(list* list symbols))))
env)))
(length
object)
Applicative length
returns the (exact) improper-list length of object.
That is, it returns the number of consecutive cdr references
that can be followed starting from object.
If object is not a pair, it returns 0
;
($define! length
($lambda (object)
($if (pair? object)
(+ 1 (length (cdr object)))
0)
))
(append .
lists)
The append
applicative returns a freshly allocated list
of the elements of all the specified lists, in order,
except that if there is a last specified element of lists, it is not copied,
but is simply referenced by the cdr of the preceding pair (if any) in the resultant list.
($define! append
($lambda x
($if (pair? x)
(apply ($lambda (h . t)
($if (pair? t)
($if (null? h)
(apply append t)
(cons (car h) (apply append (cons (cdr h) t)))
)
h)
) x)
x)
))
(reverse
list)
The reverse
applicative returns a freshly allocated list
of the elements of list, in reverse order.
($define! reverse
(($lambda ()
($define! push-pop
($lambda (r s)
($if (null? s)
r
(push-pop
(cons (car s) r)
(cdr s)))))
($lambda (s)
(push-pop () s))
)))
(filter
predicate
list)
The filter
applicative passes each of the elements of list
as an argument to predicate,
one at a time in no particular order,
using a fresh empty environment for each call.
filter
constructs and returns a list
of all elements of list
on which predicate returned #t
,
in the same order as in list.
($define! filter
($lambda (accept? xs)
($if (null? xs)
()
(($lambda ((first . rest))
($if (eval (list (unwrap accept?) first) (make-env))
(cons first (filter accept? rest))
(filter accept? rest))
) xs)) ))
(map
applicative.
lists)
lists must be a nonempty list of lists; if there are two or more, they must all have the same length. If lists is empty, or if all of its elements are not lists of the same length, an error is signaled.
The map
applicative applies applicative element-wise
to the elements of the lists in lists
(i.e., applies it to a list of the first elements of the lists,
to a list of the second elements of the lists, etc.),
using the dynamic environment from which map
was called,
and returns a list of the results, in order.
The applications may be performed in any order,
as long as their results occur in the resultant list
in the order of their arguments in the original lists.
($provide! (map)
($define! map
(wrap ($vau (applicative . lists) env
($if (apply null? lists env)
()
(appl applicative (peel lists () ()) env)
))))
($define! peel
($lambda (((head . tail) . more) heads tails)
($if (null? more)
(list (cons head heads) (cons tail tails))
(($lambda ((heads tails))
(list (cons head heads) (cons tail tails)))
(peel more heads tails)))
))
($define! appl
($lambda (applicative (heads tails) env)
(cons
(apply applicative heads env)
($if (apply null? tails env)
()
(appl applicative (peel tails () ()) env)))
))
)
> (map + (list 1 2) (list 3 4))
(4 6)
> (map + (list 1) (list 2))
(3)
> (map + (list 1 2))
(1 2)
> (map + (list 1))
(1)
> (map + ())
()
> (map cons (list 1 2 3) (list 4 5 6))
((1 . 4) (2 . 5) (3 . 6))
> (map car (list (list 1 2) (list 3 4) (list 5 6)))
(1 3 5)
> (map cdr (list (list 1 2) (list 3 4) (list 5 6)))
((2) (4) (6))
(reduce
args
binop
zero)
args should be a list. binop should be an applicative.
If args is empty, applicative reduce
returns zero.
If args is nonempty, applicative reduce
uses binary operation binop
to merge all the elements of args into a single object,
using any associative grouping of the elements.
That is, the sequence of objects initially found in args
is repeatedly decremented in length
by applying binop to a list of any two consecutive objects,
replacing those two objects with the result
at the point in the sequence where they occurred;
and when the sequence contains only one object,
that object is returned.
($define! reduce
($lambda (args binop zero)
($if (null? args)
zero
(($lambda ((first . rest))
($if (null? rest)
first
(binop first (reduce rest binop zero)))
) args)) ))
($define! foldl
($lambda (args binop zero)
($if (null? args)
zero
(($lambda ((first . rest))
(foldl rest binop (binop zero first))
) args)) ))
($define! foldr
($lambda (args binop zero)
($if (null? args)
zero
(($lambda ((first . rest))
(binop first (foldr rest binop zero))
) args)) ))
> (reduce (list 1 2 3) cons 0)
(1 2 . 3)
> (foldl (list 1 2 3) cons 0)
(((0 . 1) . 2) . 3)
> (foldr (list 1 2 3) cons 0)
(1 2 3 . 0)
($let
⟨bindings⟩.
⟨body⟩)
⟨bindings⟩ should be a list of formal-parameter-tree/expression pairings,
each of the form (
⟨formals⟩
⟨expression⟩)
,
where each ⟨formals⟩ is a formal parameter tree.
The expression
($let ((⟨form1⟩ ⟨exp1⟩) ... (⟨formn⟩ ⟨expn⟩)) . ⟨body⟩)
is equivalent to
(($lambda (⟨form1⟩ ... ⟨formn⟩) . ⟨body⟩) ⟨exp1⟩ ... ⟨expn⟩)
Thus, the ⟨expk⟩ are first evaluated
in the dynamic environment, in any order;
then a child environment e of the dynamic environment is created,
with the ⟨formk⟩ matched in e
to the results of the evaluations of the ⟨expk⟩;
and finally the subexpressions of ⟨body⟩ are evaluated in e
from left to right, with the last (if any) evaluated as a tail context,
or if ⟨body⟩ is empty the result is #inert
.
($define! $let
($vau (bindings . body) env
(eval (cons
(list* $lambda (map car bindings) body)
(map cadr bindings)) env)
))
> ($let ((one 1) (two 2)) (list one two))
(1 2)
($let*
⟨bindings⟩.
⟨body⟩)
The binding expressions are guaranteed to be evaluated from left to right,
and each of these evaluations has access to the bindings of previous evaluations.
However, each of these evaluations takes place
in a child of the environment of the previous one,
and bindings for the previous evaluation take place in the child, too.
So, if one of the binding expressions is a $vau
or $lambda
expression,
the resulting combiner still can’t be recursive;
and only the first binding expression is evaluated in the dynamic environment.
($define! $let*
($vau (bindings . body) env
(eval ($if (null? bindings)
(list* $let bindings body)
(list $let
(list (car bindings))
(list* $let* (cdr bindings) body))
) env)))
> ($let* ((one 1) (two (+ one one))) (list one two))
(1 2)
($letrec
⟨bindings⟩.
⟨body⟩)
The binding expressions may be evaluated in any order.
None of them are evaluated in the dynamic environment,
so there is no way to capture the dynamic environment using $letrec
;
and none of the bindings are made until after the expressions have been evaluated,
so the expressions cannot see each others’ results;
but since the bindings are in the same environment as the evaluations,
they can be recursive, and even mutually recursive, combiners.
($define! $letrec
($vau (bindings . body) env
(eval (list* $let ()
(list $define!
(map car bindings)
(list* list (map cadr bindings)))
body) env)))
> ($letrec (
(odd ($lambda (x) ($if (=? x 0) #f (even (- x 1)))))
(even ($lambda (x) ($if (=? x 0) #t (odd (- x 1)))))
) (list (odd 3) (even 3)))
(#t #f)
($letrec*
⟨bindings⟩.
⟨body⟩)
The binding expressions are guaranteed to be evaluated from left to right;
each of these evaluations has access to the bindings of previous evaluations;
and the result of each evaluation is matched
in the same environment where it was performed,
so if the result is a combiner, it can be recursive.
Further, the result of each binding expression is matched separately,
so there is nothing to prevent the same symbol from occurring in more than one ⟨formals⟩.
However, since each evaluation takes place in a child of the previous one,
and even the first does not take place in the dynamic environment,
there is no way to capture the dynamic environment using $letrec*
,
and no way for combiners resulting from different binding expressions to be mutually recursive.
($define! $letrec*
($vau (bindings . body) env
(eval ($if (null? bindings)
(list* $letrec bindings body)
(list $letrec
(list (car bindings))
(list* $letrec* (cdr bindings) body))
) env)))
($let-redirect
⟨env-exp⟩
⟨bindings⟩.
⟨body⟩)
The binding expressions are evaluated in the dynamic environment, but the local environment is a child of the environment resulting from evaluating ⟨env-exp⟩. This promotes semantic stability, by protecting the meaning of expressions in the body from unexpected changes to the client’s environment (much as static scoping protects explicitly constructed compound combiners).
In the interests of maintaining clarity and orthogonality of semantics,
there are no variants of $let-redirect
analogous to
the variants $let*
, etc., of $let
.
The variants of $let
modulate its role
in locally augmenting the current environment,
whereas the primary purpose of $let-redirect
is presumed to be locally replacing the current environment;
so it was judged better to provide just one environment replacement device,
insulating it as much as possible from complexities of environment augmentation.
($define! $let-redirect
($vau (env-exp bindings . body) env
(eval (list*
(eval (list* $lambda (map car bindings) body) (eval env-exp env))
(map cadr bindings))
env)))
($let-safe
⟨bindings⟩.
⟨body⟩)
The expression
($let-safe ⟨bindings⟩ . ⟨body⟩)
is equivalent to
($let-redirect (make-standard-env) ⟨bindings⟩ . ⟨body⟩)
($define! $let-safe
($vau (bindings . body) env
(eval
(list* $let-redirect (make-standard-env) bindings body)
env)))
($remote-eval
⟨exp⟩
⟨env-exp⟩)
Operative $remote-eval
evaluates ⟨exp⟩ as a tail context,
in the environment that must result from
the evaluation of ⟨env-exp⟩ in the dynamic environment.
($define! $remote-eval
($vau (o e) d
(eval o (eval e d))))
($bindings->env .
⟨bindings⟩)
The expression
($bindings->env . ⟨bindings⟩)
is equivalent to
($let-redirect (make-env) ⟨bindings⟩ (get-current-env))
($define! $bindings->env
($vau bindings denv
(eval (list
$let-redirect
(make-env)
bindings
(list get-current-env))
denv)))
(not?
boolean)
Applicative not?
is a predicate
that returns the logical negation of its argument.
($define! not? ($lambda (x) ($if x #f #t)))
(and?
boolean)
Applicative and?
is a predicate
that returns #t
unless one or more of its arguments are #f
.
($define! and?
($lambda args
(eval (cons $and? args) (get-current-env)) ))
(or?
boolean)
Applicative or?
is a predicate
that returns #f
unless one or more of its arguments are #t
.
($define! or?
($lambda args
(eval (cons $or? args) (get-current-env)) ))
($and? .
⟨objects⟩)
Operative $and?
is a predicate that
evaluates its operands from left to right,
until either an operand evaluates to #f
(result is #f
),
or the end of the list is reached (result is #t
).
If the an operand does not evaluate to a boolean,
an error is signaled.
($define! $and?
($vau x e
($cond
((null? x) #t)
((null? (cdr x)) (eval (car x) e)) ; tail context
((eval (car x) e) (apply (wrap $and?) (cdr x) e))
(#t #f)
)))
($or? .
⟨objects⟩)
Operative $or?
is a predicate that
evaluates its operands from left to right,
until either an operand evaluates to #t
(result is #t
),
or the end of the list is reached (result is #f
).
If the an operand does not evaluate to a boolean,
an error is signaled.
($define! $or?
($vau x e
($cond
((null? x) #f)
((null? (cdr x)) (eval (car x) e)) ; tail context
((eval (car x) e) #t)
(#t (apply (wrap $or?) (cdr x) e))
)))
(dump-bytes
address
count)
The dump-bytes
applicative prints a byte dump to the console,
starting at address and continuing for count bytes.
> (dump-bytes #xc000 64)
0000c000 1c f0 9c e5 6c 69 73 74 00 00 00 00 00 00 00 00 |....list........|
0000c010 00 00 00 00 00 00 00 00 00 00 00 00 a0 8d 00 00 |................|
0000c020 1c f0 9c e5 65 78 69 74 00 00 00 00 00 00 00 00 |....exit........|
0000c030 00 00 00 00 00 00 00 00 00 00 00 00 a0 8d 00 00 |................|
(load-bytes
address
count)
The load-bytes
applicative constructs and returns a list of exact integers
representing the data bytes found in system memory
starting at address and continuing for length bytes.
(store-bytes
address
list)
The store-bytes
applicative takes a list of exact integers
representing the data bytes to be stored in system memory
starting at address.
The result returned by store-bytes
is #inert
.
WARNING! This is a dangerous operation. Be careful!
(dump-words
address
count)
The dump-words
applicative prints a 32-bit word dump to the console,
starting at address and continuing for count words.
The address must be aligned on a 4-byte boundary.
> (dump-words #xd000 32)
0000_
_d000: e59cf01c 706d7564 7479622d 00007365 00000000 00000000 00000000 00008ee0
_d020: e59cf01c 74697865 00000000 00000000 00000000 00000000 00000000 00008ee0
_d040: e59cf01c 0000d000 0000d080 bbbbbbbb cccccccc dddddddd eeeeeeee 00008f60
_d060: e59cf01c 0000d000 aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee 00008d10
(load-words
address
count)
The load-words
applicative constructs and returns a list of exact integers
representing the 32-bit words found in system memory
starting at address and continuing for count words.
The address must be aligned on a 4-byte boundary.
(store-words
address
list)
The store-words
applicative takes a list of exact integers
representing the 32-bit words to be stored in system memory
starting at address.
The address must be aligned on a 4-byte boundary.
The result returned by store-words
is #inert
.
WARNING! This is a dangerous operation. Be careful!
(address-of
object)
The address-of
applicative returns an exact integer
representing the address of object.
(content-of
address)
The content-of
applicative returns the object at address.
WARNING! This is a dangerous operation. Be careful!
(dump-env
environment)
The dump-words
applicative prints an environment dump to the console.
> (dump-env (get-current-env))
0000e8a0: get-current-env = #wrap@0000edc0[0000ee00]
0000ee60: cdr = #wrap@0000ed60[0000ed80]
0000ee40: car = #wrap@0000ed00[0000ed20]
0000eea0: --scope--
0000e880: list = #wrap@00008fa0[00008f00]
0000e840: pair? = #wrap@000098e0[000098c0]
0000e800: null? = #wrap@00009920[00009900]
...
(sponsor-reserve)
The sponsor-reserve
applicative returns an exact integer
representing the address of a newly-allocated 32-byte block of memory.
(sponsor-release
address)
The sponsor-release
applicative deallocates
the previously-reserved block of memory at address.
The result is #inert
.
WARNING! This is a dangerous operation. Be careful!
(sponsor-enqueue
address)
The sponsor-enqueue
applicative adds
the previously-reserved block of memory at address
to the actor runtime message-event queue.
The result is #inert
.
WARNING! This is a dangerous operation. Be careful!
($timed .
⟨objects⟩)
The $timed
operative evaluates the elements of the list ⟨objects⟩
in the dynamic environment, one at a time from left to right (c.f.: $sequence
).
The result is the number of microseconds elapsed while performing the computation.
($define! f ($lambda (x) ($if (=? x 0) 0 (f (- x 1))) ))
> ($timed (f 1000))
1588543