[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

re: gensym and the compiler



<Mike@rice> wants to know how to make this function work:

	; construct an identity transformation matrix.
	(defun tm-new ()
	    (let ((name (gensym)))
		(*array name 'flonum-block 4 4)
		(do i 0 (1+ i) (= i 4) (store (name i i) 1.0))
		name)
	)

The problem is that send is a macro (see lisplib/array.l), and at
compile time it is impossible for it to determine exactly the "data
type" of name.  Therefore, it expands the function to:

	(defun tm-new ()
	    (let ((name (gensym)))
		(*array name 'flonum-block 4 4)
		(do i 0 (1+ i) (= i 4) (name 1.0 i i))
		name)
	)

Essentially, it just assumes 'name is a symbol which has an array in its
function binding, or else which symevals (possibly recursively) to
something that is either an array, or a symbol with an array in its
function binding.  When the compiler compiles the expansion, it assumes
that it wants to call the function-binding of name, not the
function-binding of symeval of name.  In the interpreter it happens to
work because eval of a list in the interpreter (but not the compiler) is
defined to repetitively evaluate the car of the list until it finds a
recognizable function or array.  (See chapter 4.)  But note!!  If 'name
also has a function binding, the interpreter will find it instead of the
array!

What you really want to do, then, is this:

	(defun tm-new ()
	    (let ((name (gensym)))
		(*array name 'flonum-block 4 4)
		(do i 0 (1+ i) (= i 4) (funcall name 1.0 i i))
		name)
	)

This guarantees that name gets symevaled once before the interpreter
checks for function bindings, which also does the right thing in
compiled code.  Unfortunately, you will have to write this out by hand.
I don't see any way that the send macro can be fixed.  If it always
returned the extra funcall, then this simple case wouldn't work
compiled:

	(array foo ...)
	(store foo ...)

Did anyone follow any of this?