Calls to load or require occurring at the top level of a
file being compiled are ignored. Calls to load or require
within a procedure are compiled to call (interpreted) load or
require as appropriate.
Several SCM and SLIB extensions to the Scheme report are recognized by hobbit as Scheme primitives.
The Common-lisp style defmacro implemented in SCM is recognized and procedures defined by defmacro are expanded during compilation.
Note Bene: any macro used in a compiled file must be also defined in one of the compiled files.
`#.<expression>' is read as the object resulting from the evaluation of <expression>. The calculation is performed during compile time. Thus <expression> must not contain variables defined or set! in the compiled file.
Real-only versions of transcedental procedures (warning: these procedures are not compiled directly into the corresponding C library procedures, but a combination of internal SCM procedures, guaranteeing exact correspondence with the SCM interpreter while hindering the speed):
real-sqrt real-exp real-ln real-expt real-sin real-cos real-tan real-asin real-acos real-atan real-sinh real-cosh real-tanh real-asinh real-acosh real-atanh
Note Bene: These procedures are compiled to faster code than the corresponding generic versions sqrt, abs, ... expt.
A selection of other extra primitives in SCM is also recognized as primitives. eg. get-internal-run-time, quit, abort, restart, chdir, delete-file, rename-file.
The following bitwise procedures in the scheme library file `logical.scm' are compiled directly to fast C operations on immediate integers (small 30-bit integers) (Scheme library funs in the upper row, C ops below):
logand logior logxor lognot logsleft logsright
& | ^ ~ << >>
The following alternative names logical:logand, logical:logior, logical:logxor, logical:lognot, and ash are compiled for the generic case, not immediate-integers-only and are thus much slower.
Notice that the procedures logsleft, logsright are NOT in the the library file `logical.scm:' the universal procedure ash is instead. Procedures ash, logcount, integer-length, integer-expt, bit-extract, ipow-by-squaring, in `logical.scm' are not primtives and they are all compiled into calls to interpreted code.
logsleft and logsright are defined for non-compiled use in the file `scmhob.scm' included in the SCM distribution.
The following primitives are for immediate (30-bit) integer-only arithmetics. The are compiled directly into the corresponding C operations plus some bitshifts if necessary. They are good for speed in case the compiled program uses BOTH generic arithmetics (reals, bignums) and immediate (30-bit) integer arithmetics. These procedures are much faster than corresponding generic procedures taking also reals and bignums. There is no point in using these unless the program as a whole is compiled using generic arithmetics, since otherwise all the arithmetics procedures are compiled directly into corresponding C operations anyway.
Note Bene: These primitives are NOT defined in SCM or its libraries. For non-compiled use they are defined in the file `scmhob.scm' included in the SCM distribution.
%negative? %number? %> %>= %= %<= %< %positive? %zero? %eqv? %+ %- %* %/
The nonessential procedure force and syntax delay are
implemented exactly as suggested in the report 4. This implementation
deviates internally from the implementation of force and
delay in the SCM interpeter, thus it is incorrect to pass a
promise created by delay in the compiled code to the force
used by interpreter, and vice-versa for the promises created by the
interpreter.
The following suggestions may help you to write well-optimizable and fast code for the hobbit-scm combination. Roughly speaking, the main points are:
Here come the details.
%=, %<=, %+, %*,
... for speed-critical parts of the program whenever possible.
Also, if you use bitwise logical operations, try to use the
immediate-integer-only versions
logand logior logxor lognot logsleft logsrightand not
logical:logand or ash, for example.
(set! bar +) (set! f (lambda (x) (if (zero? x) 1 (* x (f (- x 1))))))anywhere in the compiled program. Avoid using compiler flags (see section Hobbit Options):
(define compile-all-proc-redefined t) (define compile-new-proc-redefined t)
(define bar (lambda ...))or
(define (bar ...) ...)on top level and bar is not redefined anywhere.
(define (member-if fn lst)
(if (fn (car lst))
lst
(member-if fn (cdr lst)) ))
member-if-not is not a clonable HOP (fn occurs in a lambdaterm):
(define (member-if-not fn lst) (member (lambda (x) (not (fn x))) lst) )show-f is not a clonable HOP (fn occurs in a non-function position in (display fn)):
(define (show-f fn x)
(set! x (fn x))
(display fn)
x)
(define plus
(lambda (x)
(lambda (y) (+ y x)) ))
returns a procedure.
(define foo (lambda ...)), (let ((x 1) (f (lambda ...))) ...) (let* ((x 1) (f (lambda ...))) ...) (let name ((x 1) (f (lambda ...))) ...) (letrec ((f (lambda ...)) (g (lambda ...))) ...)or as arguments to clonable HOP-s or primitives map and for-each, like
(let ((x 0)) (map (lambda (y) (set! x (+ 1 x)) (cons x y)) list)) (member-if (lambda (x) (< x 0)) list)where member-if is a clonable HOP. Also, avoid using variables with a procedural value anywhere except in a function position (first element of a list) or as an argument to a clonable HOP, map or for-each. Lambda-terms conforming to the current point are said to be liftable. Examples:
(define (bar x) (let ((f car)) (f (f x))))has `car' in a non-function and non-HOP-argument position in
(f car), thus it is slower than
(define (bar x) (let ((f 1)) (car (car x))))Similarly,
(define (bar y z w)
(let ((f (lambda (x) (+ x y))))
(set! w f)
(cons (f (car z))
(map f z) )))
has `f' occurring in a non-function position in (set! w f),
thus the lambda-term (lambda (x) (+ x y)) is not liftable and the
upper `bar' is thus slower than the following equivalent `bar'
with a liftable inner lambda-term:
(define (bar y z w)
(let ((f (lambda (x) (+ x y))))
(set! w 0)
(cons (f (car z))
(map f z) )))
Using a procedure bar defined as
(define bar (let ((x 1)) (lambda (y) (set! x y) (+ x y))))is slower than using a procedure bar defined as
(define *bar-x* 1) (define bar (lambda (y) (set! *bar-x* y) (+ *bar-x* y)))since the former definition contains a non-liftable lambda-term.
(verbose 3) to see the
amount of time used by garbage collection while your program is running.
Try to minimize the amount of creating new vectors, strings and symbols
in the speed-critical program frgaments, that is, a number of
applications of make-vector, vector, list->vector,
make-string, string-append, *->string, string->symbol.
Creating such objects takes typically much more time than consing.