Previous: Force and Delay, Up: The Language Compiled [Contents][Index]
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 logsright
and 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 Hobbit Options):
(define compile-all-proc-redefined t) (define compile-new-proc-redefined t)
A higher-order procedure (HOP for short) is defined as a procedure with some of its formal arguments occuring in the procedure body in a function position, that is, as a first element of a list. Such an argument is called a higher-order argument.
A HOP ‘bar’ is clonable iff it satisfies the following four conditions:
(define bar (lambda …))
or
(define (bar …) …)
on top level and bar is not redefined anywhere.
Examples:
If ‘member-if’ is defined on top level and is not redefined anywhere, then ‘member-if’ is a clonable HOP:
(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)
Eg, a procedure
(define plus (lambda (x) (lambda (y) (+ y x)) ))
returns a procedure.
In speed-critical parts avoid using lambda-terms except in non-set! function definitions like
(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.
Declare globally defined variables which are never set! or redefined and whose value is a small integer, character or a boolean, as being inlinable. See Hobbit Options.
In addition, take the following into account:
Hobbit guarantees proper tailrecursive behaviour for non-mutual tailrecursion (foo calling foo tailrecursively), provided that foo is not redefined anywhere and that foo is not a local function which occurs also in a non-function and non-clonable-HOP-argument position (i.e. cases 3 and 6 above).
Previous: Force and Delay, Up: The Language Compiled [Contents][Index]