From: Albert Reiner
Subject: (let (a b c) (let (d) ...)) vs. (let (a b c d) ...)
Date: 
Message-ID: <m1d68gzbt9.fsf@reiner.chello.at>
Hi,

first of all, thanks to those who pointed out the relevant CLiki page for my
last question.

Now, however, I have come across something I find extremely puzzling, and I
suspect there is something fundamental I don't understand about Lisp, (let) in
particular.

I have written some code that works well as long as it is interpreted.  As
soon as it is compiled, though, I get strange errors like:

________________________________________________________________
Error in function C::FIND-IN-ENVIRONMENT:

     #<C::LAMBDA-VAR #x485C9E65  NAME= #:DLEFT121>
     not found in
     #<C::ENVIRONMENT #x488ED8D5
         FUNCTION= #<LAMBDA #x484995D5
                       NAME= NIL
                       TYPE= #<FUNCTION-TYPE (FUNCTION NIL LIST)>
                       WHERE-FROM= :DEFINED
                       VARS= NIL>
         NLX-INFO= (#<C::NLX-INFO #x489073BD
                        CONTINUATION= #<Continuation c1>
                        TARGET= #<C::CBLOCK Start = c2 {4890742D}>
                        INFO= #<C::IR2-NLX-INFO #x4890C665
                                  HOME= NIL
                                  SAVE-SP= #<TN t1>
                                  DYNAMIC-STATE= (#<TN t2> #<TN t3> #<TN t4>
                                                  #<TN t5>)>>)>

Restarts:
  0: [ABORT] Return to Top-Level.

Debug  (type H for help)

(C::FIND-IN-ENVIRONMENT #<C::LAMBDA-VAR #x485C9E65  NAME= #:DLEFT121>
                        #<C::ENVIRONMENT #x488ED8D5
                            FUNCTION= #<LAMBDA #x484995D5
                                          NAME= NIL
                                          TYPE= #<FUNCTION-TYPE #>
                                          WHERE-FROM= :DEFINED
                                          VARS= NIL>
                            NLX-INFO= (#<C::NLX-INFO 489073BD>)>)
Source: Error finding source: 
Error in function DEBUG::GET-FILE-TOP-LEVEL-FORM:  Source file no longer exists:
  target:compiler/ir2tran.lisp.
0] 
________________________________________________________________


The error can be traced back to the only place where I use some symbol (gensym
"DLEFT"), specifically to the use of ,dleft in ,try marked with "problem
here!":

________________________________________________________________
(defmacro with-find-min-token-functions
  (name->                       ; args: (digit &optional hints values)
   name-=                       ; args: (digit &optional hints values)
   (natdigit tMin tMax)
   &body body)
  "purpose: see below[1]"
  (with-gensyms
   (try dleft dright tleft tright leftp rightp
        tok d dNat hint hints-and-vals)
   `(let (,dleft ,dright ,tleft ,tright ,leftp ,rightp) ; <--- the LET
      (labels
          ((,name-> (,d &optional ,hints-and-vals)
                    (setq ,leftp nil)
                    (setq ,rightp nil)
                    (setq ,tleft (1- ,tMin))
                    (setq ,tright (1+ ,tMax))
                    (dolist (,hint ,hints-and-vals)
                      (,try ,d (car ,hint) (cdr ,hint)))
                    (,try ,d (truncate (+ ,tleft ,tright) 2))
                    (,try ,d (1+ ,tleft)) ; tMin or higher
                    (,try ,d (1- ,tright)) ; tMax or lower
                    (cond
                     ((and ,leftp ,rightp) ;; tleft+1 .. tright
                      (loop
                       (when (= 1 (- ,tright ,tleft))
                         (return-from ,name->
                           (values ,tright ,dright)))
                       (,try ,d (truncate (+ ,tleft 1 ,tright) 2))
                       ))
                     (,rightp ;; tMin
                      (return-from ,name->
                        (values ,tMin (,natdigit ,tMin))))
                     (,leftp ;; tMax+1 (for ...-= only)
                      (return-from ,name->
                        (values (1+ ,tMax) nil)))
                     (t (error "Bug (with-find-min-token-functions): >."))))
           (,try (,d ,tok &optional ,dNat)
                 (when (< ,tleft ,tok ,tright)
                   (let ((,dNat (or ,dNat (,natdigit ,tok))))
                     (cond
                      ((> ,dNat ,d)
                       (setq ,rightp t)
                       (setq ,tright ,tok)
                       (setq ,dright ,dNat))
                      (t
                       (setq ,leftp t)
                       (setq ,tleft ,tok)
                       (setq ,dleft ,dNat)))))) ;  <------- problem here!
           (,name-= (,d &optional ,hints-and-vals)
                    (multiple-value-bind
                        (,tok ,dNat)
                        (,name-> (1- ,d) ,hints-and-vals)
                      (assert (= ,d ,dNat))
                      ,tok)))
        ,@body))))
________________________________________________________________

Unless emacs is fooling me, the parentheses work out so that all of the
(labels), including ,try and ,@body, are in the scope of the (let). -
(with-gensyms) is simply:

________________________________________________________________
(defmacro with-gensyms (syms &body body)
  `(let ,(mapcar
          #'(lambda (v) (list v (list 'gensym (symbol-name v))))
          syms)
     ,@body))
________________________________________________________________

I know that it is the use of ,dleft in ,try that causes the problem, as
functions using these macros compile fine (but obviously do not work) when I
comment out the t-branch of the cond in ,try.

All this is on binary installs [3] of CMUCL 18e on two different Linux
systems, which should rule out, e.g., bad memory as the source.  As the full
code is quite voluminous and only partly relevant to this problem, I don't
post it here [2].

Of course, as I have been using Lisp for only a couple of days, I am sure my
code is horrid and inefficient and what-have-you.  However, what really
puzzles me is that I have found a number of ways of getting the function to
compile simply by changing the (let) statement marked "the LET" above:

- When I replace it with

    (let* (,dleft ,dright ,tleft ,tright ,leftp ,rightp) ...)

  , everything compiles fine; the position of ,dleft does not matter.  As far
  as I understand, the difference between let and let* is only the
  initialization of the variable, but none of them are initialized to anything
  but nil in this code.

- I have looked at a number of variations of the kind

    (let (<first group>)
      (let (<second group>) ... ))

  , where both groups together comprise the same set of variables as
  before. By experimentation I found that a function using
  with-find-min-token-functions only compiles when ,dleft is in either of the
  two groups by itself, with all of the other symbols in the other group,
  i.e., when I have

    (let (,dleft)
      (let (,dright ,tleft ,tright ,leftp ,rightp) ... ))

  or

    (let (,dright ,tleft ,tright ,leftp ,rightp)
      (let (,dleft) ... ))

  .  Again, I do not see why ,dleft would have to be initialized to nil
  separately from the other five symbols.

In general, it is my current - apparently erroneous - understanding that
neither the order of the variables, nor the difference between let and let*,
nor a subdivision of all the variables in separate groups bound by nested lets
can make a difference in the absence of initialization forms.  The unexpected
failure to compile, however, clearly indicates otherwise.

Currently I am extremely puzzled, and I would be most grateful for any light
you can (and decide to) shed.  Regards,

Albert.


_______________

[1] natdigit(t) is a monotonously increasing function mapping integers t to
integers d in some range; the functions bound to ,name-= and ,name-> return
the smallest t such that natdigit(t) equals or exceeds a given integer d.

[2] Available from
<http://tph.tuwien.ac.at/~areiner/20040215-0/quidquid.tar.bz2>. After loading
baseencode.lisp and hrt-decode.lisp, with the sample data of .Iso.00012 I
tried to compile various statements, as can be found from the file log.

[3] The tarballs and their md5 checksums:

    b04a7ad4172b22faf5f536fe028a157a  cmucl-18e-x86-linux.extra.tar.bz2
    695f4a6abc5af6276f776a9739c2c7e7  cmucl-18e-x86-linux.tar.bz2
    f2d46f8bcee4d66598f294473bd73de6  cmucl-18e.documents.tar.bz2

I obtained them via the CMUCL home page on January 26.

From: Paul F. Dietz
Subject: Re: (let (a b c) (let (d) ...)) vs. (let (a b c d) ...)
Date: 
Message-ID: <HpOdnYiq9ap-4bLdRVn-uQ@dls.net>
Albert Reiner wrote:

> Now, however, I have come across something I find extremely puzzling, and I
> suspect there is something fundamental I don't understand about Lisp, (let) in
> particular.
> 
> I have written some code that works well as long as it is interpreted.  As
> soon as it is compiled, though, I get strange errors like:
> 
> ________________________________________________________________
> Error in function C::FIND-IN-ENVIRONMENT:
> 
>      #<C::LAMBDA-VAR #x485C9E65  NAME= #:DLEFT121>
>      not found in
>      #<C::ENVIRONMENT #x488ED8D5
[...]


That's a compiler bug (in CMUCL, right?)  You might try a more recent
CMUCL binary.

	Paul
From: Albert Reiner
Subject: Re: (let (a b c) (let (d) ...)) vs. (let (a b c d) ...)
Date: 
Message-ID: <m11xot53bu.fsf@reiner.chello.at>
"Paul F. Dietz" <·····@dls.net> writes:

> > I have written some code that works well as long as it is interpreted.  As
> > soon as it is compiled, though, I get strange errors like:
> [...]
> That's a compiler bug (in CMUCL, right?)  You might try a more recent
> CMUCL binary.
> 
> 	Paul

Thanks a lot: I got the 2003-11 snapshot, and not only does (let) again work
as I expected, the very same code is also faster by more than an order of
magnitude (though the Fortran code is still about 7.3 times faster).

Albert.
From: Raymond Toy
Subject: Re: (let (a b c) (let (d) ...)) vs. (let (a b c d) ...)
Date: 
Message-ID: <4n7jylg5yn.fsf@edgedsp4.rtp.ericsson.se>
>>>>> "Albert" == Albert Reiner <······@chello.at> writes:

    Albert> "Paul F. Dietz" <·····@dls.net> writes:
    >> > I have written some code that works well as long as it is interpreted.  As
    >> > soon as it is compiled, though, I get strange errors like:
    >> [...]
    >> That's a compiler bug (in CMUCL, right?)  You might try a more recent
    >> CMUCL binary.
    >> 
    >> Paul

    Albert> Thanks a lot: I got the 2003-11 snapshot, and not only does (let) again work
    Albert> as I expected, the very same code is also faster by more than an order of
    Albert> magnitude 

This seems unlikely.  I don't think there's been any such major
improvement in the compiler.  I haven't tested, but I suspect even the
old 17f version isn't really much worse than the 2003-11 snapshot.

    Albert> (though the Fortran code is still about 7.3 times faster).

This is certainly possible, depending on what you're doing, and
whether you've declared everything.

Ray
From: Albert Reiner
Subject: Re: (let (a b c) (let (d) ...)) vs. (let (a b c d) ...)
Date: 
Message-ID: <m1ptcdd6rn.fsf@reiner.chello.at>
Raymond Toy <···@rtp.ericsson.se> writes:

>     Albert> Thanks a lot: I got the 2003-11 snapshot, and not only does (let) again work
>     Albert> as I expected, the very same code is also faster by more than an order of
>     Albert> magnitude 
> 
> This seems unlikely.  I don't think there's been any such major
> improvement in the compiler.  I haven't tested, but I suspect even the
> old 17f version isn't really much worse than the 2003-11 snapshot.

Actually, I only changed the (let*) back to the (let) I had before (see
original post).  With this exception, the code was exactly the same, and of
course I used the same input on the same machine, with otherwise negligible
system load.  With CMUCL 18e it took around 4.5 seconds, and around 0.35 with
2003-11.  For the latter, the ratio to Fortran stays in the range of 1:7 to
1:8 even for much larger input data sets where the runtimes are several
minutes, but obviously I didn't test that with 18e.

>     Albert> (though the Fortran code is still about 7.3 times faster).
> 
> This is certainly possible, depending on what you're doing, and
> whether you've declared everything.

I haven't, yet.

Anyway, I am glad that even my first attempt at CL is not *that* much slower
than a rather careful Fortran implementation, but of course the speed-up may
not be typical.

Albert.
From: Simon Adameit
Subject: Re: (let (a b c) (let (d) ...)) vs. (let (a b c d) ...)
Date: 
Message-ID: <pan.2004.02.17.17.26.22.674806@gmx.net>
On Tue, 17 Feb 2004 16:12:25 +0000, Albert Reiner wrote:

> Raymond Toy <···@rtp.ericsson.se> writes: 
>> This seems unlikely.  I don't think there's been any such major
>> improvement in the compiler.  I haven't tested, but I suspect even the
>> old 17f version isn't really much worse than the 2003-11 snapshot.
> 
> Actually, I only changed the (let*) back to the (let) I had before (see
> original post).  With this exception, the code was exactly the same, and of
> course I used the same input on the same machine, with otherwise negligible
> system load.  With CMUCL 18e it took around 4.5 seconds, and around 0.35 with
> 2003-11.  For the latter, the ratio to Fortran stays in the range of 1:7 to
> 1:8 even for much larger input data sets where the runtimes are several
> minutes, but obviously I didn't test that with 18e.
> 

As far as I understood this the 4.5 seconds with cmucl 18e where
interpreted code and the 0.35 with the snapshot compiled. I think this is
where the speed difference is coming from.

Simon
From: Albert Reiner
Subject: Re: (let (a b c) (let (d) ...)) vs. (let (a b c d) ...)
Date: 
Message-ID: <m1ptcdwnvp.fsf@reiner.chello.at>
Simon Adameit <·······@gmx.net> writes:

> As far as I understood this the 4.5 seconds with cmucl 18e where
> interpreted code and the 0.35 with the snapshot compiled. I think this is
> where the speed difference is coming from.
> 
> Simon

Actually, no: The interpreted code was much slower (on the order of minutes, I
don't recall exactly), and I was quite disappointed.  So I wanted to find out
just _how_ slow, and called it via (time ...) instead, which wrapped it in
(lambda () ...), compiled that and thereby triggered the compiler error.  I
did exactly the same, i.e., called the code via time, with the snapshot; of
course it might be that the time macro has changed, I don't know.

Albert.