[iterate-devel] Fwd: iterate form evaluates but does not load into sbcl fasl
Hello, (A copy of this email was recently sent to the gsll and sbcl mailing lists). The package gsd <http://repo.or.cz/w/gsd.git>, part of gsll<http://common-lisp.net/project/gsll/>uses iterate to loop over elements of vectors and matrices. I have attached the part of the package that extends iterate to this email. I am having the following issue on sbcl1.034 on RHEL5 64-bit linux, via slime. The following form evaluates OK at the REPL. (iter:iter (iter:for c :matrix-row grid::*array-3-4-double-float* ) (print c)) But, if I embed it into a function: (defun foo () (iter:iter (iter:for c :matrix-row grid::*array-3-4-double-float*) (print c))) it will evaluate OK in slime (C-x C-e), but will not compile (C-c C-c). The returned error is:
post-processing/xpdp-post-processing.lisp:75:3: error: Objects of type FUNCTION can't be dumped into fasl files. --> LET* BLOCK TAGBODY PROGN SETQ THE FUNCALL SB-C::%FUNCALL THE --> SB-KERNEL:%COERCE-CALLABLE-TO-FUN ==> #<FUNCTION (LAMBDA #) {1002DD7AD9}> note: The first argument never returns a value. --> LET* BLOCK TAGBODY PROGN SETQ THE FUNCALL SB-C::%FUNCALL THE ==> (SB-KERNEL:%COERCE-CALLABLE-TO-FUN #<FUNCTION # {1002DD7AD9}>) ... more stuff
So, it seems that sbcl can digest it, but for some reason cannot write it to a fasl. The macroexpansion of the code above is: (LET* ((#:SEQUENCE120 NIL) (#:LIMIT121 NIL) (C NIL) (#:INDEX119 NIL)) (BLOCK NIL (TAGBODY (PROGN (SETQ #:SEQUENCE120 GRID::*ARRAY-3-4-DOUBLE-FLOAT*) (SETQ #:LIMIT121 (FUNCALL # #:SEQUENCE120)) (SETQ #:INDEX119 -1)) LOOP-TOP-NIL (PROGN (SETQ #:INDEX119 (+ #:INDEX119 1)) (IF (>= #:INDEX119 #:LIMIT121) (GO LOOP-END-NIL)) (SETQ C (FUNCALL # #:SEQUENCE120 #:INDEX119)) (PRINT C)) (PROGN) (GO LOOP-TOP-NIL) LOOP-END-NIL (PROGN)) NIL)) Is this issue due to a malformed extension of iterate, or some misalignment between iterate and sbcl? Thank you, Mirko
On 2/9/10, Mirko Vukovic <mirko.vukovic@gmail.com> wrote:
Hello,
(A copy of this email was recently sent to the gsll and sbcl mailing lists).
The package gsd <http://repo.or.cz/w/gsd.git>, part of gsll<http://common-lisp.net/project/gsll/>uses iterate to loop over elements of vectors and matrices. I have attached the part of the package that extends iterate to this email.
I am having the following issue on sbcl1.034 on RHEL5 64-bit linux, via slime.
The following form evaluates OK at the REPL. (iter:iter (iter:for c :matrix-row grid::*array-3-4-double-float* ) (print c))
But, if I embed it into a function: (defun foo () (iter:iter (iter:for c :matrix-row grid::*array-3-4-double-float*) (print c)))
it will evaluate OK in slime (C-x C-e), but will not compile (C-c C-c). The returned error is:
post-processing/xpdp-post-processing.lisp:75:3: error: Objects of type FUNCTION can't be dumped into fasl files. --> LET* BLOCK TAGBODY PROGN SETQ THE FUNCALL SB-C::%FUNCALL THE --> SB-KERNEL:%COERCE-CALLABLE-TO-FUN ==> #<FUNCTION (LAMBDA #) {1002DD7AD9}>
note: The first argument never returns a value. --> LET* BLOCK TAGBODY PROGN SETQ THE FUNCALL SB-C::%FUNCALL THE ==> (SB-KERNEL:%COERCE-CALLABLE-TO-FUN #<FUNCTION # {1002DD7AD9}>)
... more stuff
Hi Mirko, I didn't actually look into this, but it sounds like a problem with externalising literal functions. Unlike, SBCL, clisp (the implementation) doesn't seem to have this problem (or at least I could reproduce it). See this snippet below: (defun my-car (x) (macrolet ((m () `(funcall ,#'car x))) (m))) Try and COMPILE-FILE the above as a file in SBCL, and compare clisp. I believe this is related to the reason why some Lispers often write (funcall 'some-function ...) instead of (funcall #'some-function ...), since symbols are externalisable. For more details, check out the hyperspec entry for compile-file, and look for the link on "Literal Objects in Compiled Files". I hope my hunch about this is correct, caveat emptor!
So, it seems that sbcl can digest it, but for some reason cannot write it to a fasl.
The macroexpansion of the code above is: (LET* ((#:SEQUENCE120 NIL) (#:LIMIT121 NIL) (C NIL) (#:INDEX119 NIL)) (BLOCK NIL (TAGBODY (PROGN (SETQ #:SEQUENCE120 GRID::*ARRAY-3-4-DOUBLE-FLOAT*) (SETQ #:LIMIT121 (FUNCALL # #:SEQUENCE120)) (SETQ #:INDEX119 -1)) LOOP-TOP-NIL (PROGN (SETQ #:INDEX119 (+ #:INDEX119 1)) (IF (>= #:INDEX119 #:LIMIT121) (GO LOOP-END-NIL)) (SETQ C (FUNCALL # #:SEQUENCE120 #:INDEX119)) (PRINT C)) (PROGN) (GO LOOP-TOP-NIL) LOOP-END-NIL (PROGN)) NIL))
That # #:SEQUENCE120 looks funny. Is it meant to be #'#:SEQUENCE120? Maybe it's not what I thought it was...
Is this issue due to a malformed extension of iterate, or some misalignment between iterate and sbcl?
Thank you,
Mirko
Anyway, hope this might help. Yong.
On 2/9/10, szergling <senatorzergling@gmail.com> wrote: <<snip>>
literal functions. Unlike, SBCL, clisp (the implementation) doesn't seem to have this problem (or at least I could reproduce it). See this snippet below:
Correction: Unlike SBCL, clisp (the implementation) doesn't seem to have this problem (or at least I couldn't reproduce it). Apologies for the poor and hasty writing. Yong.
The iterate extension is clearly wrongly written. You cannot insert non- externalisable value into the compiled file, in this case, functions compiled in compilation-environment. The code should be rewritten to use defuns to declare functions and to use symbols in defclause-sequence.
On Mon, Feb 8, 2010 at 9:57 PM, Kalyanov Dmitry <kalyanov.dmitry@gmail.com>wrote:
The iterate extension is clearly wrongly written. You cannot insert non- externalisable value into the compiled file, in this case, functions compiled in compilation-environment. The code should be rewritten to use defuns to declare functions and to use symbols in defclause-sequence.
Dmitry, Yesterday was the first time I encountered this externalisation issue (see emails by Yong). So, I am still wobbly with these concepts. Are you implying that instead of lambda forms one should define the functions and use function names. For example, in the following form (defclause-sequence matrix-row matrix-row-index :access-fn (lambda (marray index) (check-type marray gsl:matrix) (gsll:row marray index)) :size-fn (lambda (marray) (check-type marray gsl:matrix) (c-array:dim0 marray)) :element-type t :sequence-type t :element-doc-string "(copied) rows of a matrix" :index-doc-string "index of the rows in a matrix") all lambda expressions need to be replaced by function symbols. Correct? FWIW, I could not reproduce my problem on clisp. Mirko
Mirko,
Are you implying that instead of lambda forms one should define the functions and use function names. No. Just look at the examples in the source code, incl. tests. The key is to write #'(lambda ...) aka. (function (lambda ...)), not (lambda ...)
Remember that Iterate is based on a code walker, macrology and plumbing code snippets into other code snippets. (lambda ...) is a macro not recognized by Iterate in defclause-sequence. OTOH, function (#') is a well-known special form.
all lambda expressions need to be replaced by function symbols. Correct? Wrong. You can, you need not. #'(lambda ...) may allow better inlining, with every optimizing compiler out there.
FWIW, I could not reproduce my problem on clisp. Like others said, CLISP, based its byte code, can write an externalisation of the function to the .FAS file, but this just hides the bug in gsd's code.
Please submit a patch to the authors of gsd/gsll. BTW, I'd throw the ASSERT out of every accessor and move it into the loop initialization. Why repeat it 1000000 times when once is enough? Why is it in defclause-sequence only and not in the FOR driver? Are these remains from a debugging session? Regards, Jörg Höhle
On Tue, Feb 9, 2010 at 9:30 AM, <Joerg-Cyril.Hoehle@t-systems.com> wrote:
Mirko,
Are you implying that instead of lambda forms one should define the functions and use function names. No. Just look at the examples in the source code, incl. tests. The key is to write #'(lambda ...) aka. (function (lambda ...)), not (lambda ...)
Like this? (defclause-sequence matrix-row matrix-row-index :access-fn #'(lambda (grid index) (assert (and (grid:gridp grid) (eql (grid:grid-rank grid) 2)) (grid)) (grid:row grid index)) :size-fn #'(lambda (grid) (assert (and (grid:gridp grid) (eql (grid:grid-rank grid) 2)) (grid)) (first (grid:grid-dimensions grid))) :element-type t :sequence-type t :element-doc-string "(copied) rows of a matrix" :index-doc-string "index of the rows in a matrix") Unfortunately, that did not help improve things. Also, the iterate documentation has an example of `defclause-sequence' (bottom of p.26 of the pdf file). There is no #'(lambda ...), just plain (lambda ...) Thank you for your time, Mirko
See below for the fix. Thank's to everyone's help and suggestions. I still have only a dim understanding of what is going on. But I am only in year three of the 10-year lisp journey :-) On Tue, Feb 9, 2010 at 9:54 AM, Mirko Vukovic <mirko.vukovic@gmail.com>wrote:
On Tue, Feb 9, 2010 at 9:30 AM, <Joerg-Cyril.Hoehle@t-systems.com> wrote:
Mirko,
Are you implying that instead of lambda forms one should define the functions and use function names. No. Just look at the examples in the source code, incl. tests. The key is to write #'(lambda ...) aka. (function (lambda ...)), not (lambda ...)
Like this?
(defclause-sequence matrix-row matrix-row-index :access-fn #'(lambda (grid index) (assert (and (grid:gridp grid) (eql (grid:grid-rank grid) 2)) (grid)) (grid:row grid index)) :size-fn #'(lambda (grid) (assert (and (grid:gridp grid) (eql (grid:grid-rank grid) 2)) (grid)) (first (grid:grid-dimensions grid)))
:element-type t :sequence-type t :element-doc-string "(copied) rows of a matrix" :index-doc-string "index of the rows in a matrix")
Unfortunately, that did not help improve things.
Also, the iterate documentation has an example of `defclause-sequence' (bottom of p.26 of the pdf file). There is no #'(lambda ...), just plain (lambda ...)
Thank you for your time,
The fix was to put a single quote in front of the (lambda ...) expressions like this: (defclause-sequence matrix-row matrix-row-index :access-fn '(lambda (grid index) (assert (and (grid:gridp grid) (eql (grid:grid-rank grid) 2)) (grid)) (grid:row grid index)) :size-fn '(lambda (grid) (assert (and (grid:gridp grid) (eql (grid:grid-rank grid) 2)) (grid)) (first (grid:grid-dimensions grid))) :element-type t :sequence-type t :element-doc-string "(copied) rows of a matrix" :index-doc-string "index of the rows in a matrix") Not #'(lambda ...). The same goes for named functions. Thus 'foo and not #'foo. Mirko
participants (4)
-
Joerg-Cyril.Hoehle@t-systems.com
-
Kalyanov Dmitry
-
Mirko Vukovic
-
szergling