compilation of 
Author Message
 compilation of

Why can't you compile closures?

(let ((x 1))
  (defun dene ()
      x))

(compile 'dene)



Tue, 21 May 2002 03:00:00 GMT  
 compilation of
I forgot to mention, my platform is CMUCL solaris.

Tunc

Quote:

> Why can't you compile closures?

> (let ((x 1))
>   (defun dene ()
>       x))

> (compile 'dene)



Tue, 21 May 2002 03:00:00 GMT  
 compilation of

Quote:

> I forgot to mention, my platform is CMUCL solaris.

> Tunc


> > Why can't you compile closures?

> > (let ((x 1))
> >   (defun dene ()
> >       x))

> > (compile 'dene)

In Allegro 5.01:

IDL-USER(2): (let ((x 1))
               (defun de ()
                 x))
DE
IDL-USER(3): (compile 'de)
; While compiling DE:
Warning: Attempting to compile an interpreted closure: DE
DE
T
T
IDL-USER(4):

--
David J. Cooper Jr, Chief Engineer      Genworks International

(248) 932-2512 (Genworks HQ/voicemail)  West Bloomfield, MI 48322-2268
(248) 407-0633 (pager)                  http://www.genworks.com



Wed, 22 May 2002 03:00:00 GMT  
 compilation of

+---------------
| Why can't you compile closures?
| (let ((x 1))
|   (defun dene ()
|       x))
| (compile 'dene)
+---------------

Well, you *can*, just not exactly *that* way. ;-}  Whenever you compile
a top-level function, any closures within it also get compiled. So you
can define (and then compile) a top-level "closure generator" that does
what you want, albeit slightly awkwardly [though that can be fixed with
suitable macrology]. My normal example of such things is a generator of
counters, but let's use your example [aside: what does "dene" mean?]:

        > (defun make-dene (&key (init 0))
            (let ((x init))
              #'(lambda () x)))
        MAKE-DENE
        > (setf (symbol-function 'dene) (make-dene :init 1))
        #<Interpreted Function "LAMBDA (&KEY (INIT 0))" {90808E9}>
        > (dene)
        1
        > (describe 'dene)
        DENE is an internal symbol in the COMMON-LISP-USER package.
        Function: #<Interpreted Function "LAMBDA (&KEY (INIT 0))" {90BA369}>
        Function arguments: There are no arguments.
        Its defined argument types are: NIL
        Its result type is: *
        Its closure environment is:
          0: 1
        Its definition is:
          (LAMBDA () X)
        >

Now compile "make-dene", and see how it changes things:

        > (compile 'make-dene)
        Compiling LAMBDA (&KEY (INIT 0)):
        Compiling Top-Level Form:
        MAKE-DENE
        NIL
        NIL
        > (setf (symbol-function 'dene) (make-dene :init 23))
        #<Closure Over Function "LAMBDA (&KEY (INIT 0))" {90A5C19}>
        > (dene)
        23
        > (describe 'dene)
        DENE is an internal symbol in the COMMON-LISP-USER package.
        Function: #<Closure Over Function "LAMBDA (&KEY (INIT 0))" {90A62E1}>
        Function arguments: There are no arguments.
        Its defined argument types are: NIL
        Its result type is: T
        On Saturday, 12/4/99 02:20:12 am PST it was compiled from:
        #(#'(LAMBDA # #))
        Its closure environment is:
        0: 23
        >

Is that close enough to what you were looking for?

-Rob

-----

Applied Networking              http://reality.sgi.com/rpw3/
Silicon Graphics, Inc.          Phone: 650-933-1673
1600 Amphitheatre Pkwy.         FAX: 650-933-0511
Mountain View, CA  94043        PP-ASEL-IA



Wed, 22 May 2002 03:00:00 GMT  
 compilation of

Quote:
> Why can't you compile closures?
> (let ((x 1))
>   (defun dene ()
>       x))

I think the reason is implementational.  

Interpreted and compiled closures may have differing representations
of the closed-over environment -- typically an interpreted closure
might have some simple but low performance representation (an alist
say) whereas a compiled closure might do some much cleverer trick like
allocating a vector of objects and then compiling references into this
vector.

Compiling a closure would involve changing the representation of the
environment from one to the other.

However, if there is more than one user of the closed-over
environment, then this is fairly difficult -- the compiler *can't*
unilaterally change the representation, because the other users may
still be interpreted.  You can't take a copy of the environment when
compiling either, because that breaks the program.  And finally, you
probably can't know who all the other users are and compile them.

So compiling a closure may be implementationally very hard, and
therefore the result is left as `undefined' in the standard.

Note that this *doesn't* imply that closures are never compiled, they
just have to be compiled in such a way that the compiler can see
`enough', like this say:

        (defun make-foo (x)
          (defun foo (y)
            (+ x y)))

        (compile 'make-foo)
        (make-foo)
        ;; now FOO is a compiled closure

--tim  



Wed, 22 May 2002 03:00:00 GMT  
 compilation of

Quote:
> You can't compile an interpreted closure in any Lisp. AFAIK, it is
> basically impossible to do from an implementor's perspective. The
> standard may even be explicit about this (or have a cleanup issue or
> something--I'm too lazy to look for it). Anyways, you can do:

The standard says it is undefined.

Some implementations allow it:

    > (let ((x 1)) (defun foo (y) (+ y x)) (defun bar (y) (setf x y)))
    bar
    > (foo 1)
    2
    > (bar 2)
    2
    > (foo 1)
    3
    > (compile 'foo)
    foo
    > (foo 1)
    3
    > (bar 4)
    4
    > (foo 1)
    5

(and yes, this is an implementation with a compiler)

--tim



Wed, 22 May 2002 03:00:00 GMT  
 compilation of

Quote:
> Nope.  That doesn't work, and careful inspection reveals that
> it is no different than the original example:

> * (let ((x 1))
>     (compile (defun dene () x)))

Oops. I forgot to wrap the LET into the COMPILE. This should work:

  (funcall (compile nil (lambda () (let ((x 1)) (defun dene () x)))))

The Lisp I used for testing the original version actually accepted it....

Christopher



Wed, 22 May 2002 03:00:00 GMT  
 compilation of
Quote:

> Here is a quote from the ACL windows help file:

> "compile is rarely called since Allegro CL for Windows compiles
> everything on definition anyway."

Maybe it's true for Windows version, but:

USER(2): (lisp-implementation-version)
"5.0.1 [Linux/X86] (6/29/99 16:11)"
USER(3): (defun test (x) x)
TEST
USER(4): (compiled-function-p #'test)
NIL

--
  Eugene



Wed, 22 May 2002 03:00:00 GMT  
 compilation of

Quote:
> Why can't you compile closures?

I can't find the reference right now, but I think I read somewhere
(probably one of Graham's books) that closures can only be compiled by
COMPILE-FILE, but _not_ in the toplevel by COMPILE.

--
Frode Vatvedt Fjeld



Thu, 23 May 2002 03:00:00 GMT  
 compilation of

Quote:
> Warning: Attempting to compile an interpreted closure: DE

it warns, but id *does* compile!

--
  (espen)



Thu, 23 May 2002 03:00:00 GMT  
 compilation of

Quote:
> Here is a quote from the ACL windows help file:

> "compile is rarely called since Allegro CL for Windows compiles
> everything on definition anyway."

You're probably looking at ACL/Win 3.x documentation.  Anything 5.0
and greater does not compile automatically, whether on Unixen or on
Windows.

Quote:


> > > I believe that Allegro compiles everything by default, I remember
> > > reading about that somewhere.

> > No. The Allegro CL top-level is interpreted.

> ...

> > Christopher

--
Duane Rettig          Franz Inc.            http://www.franz.com/ (www)
1995 University Ave Suite 275  Berkeley, CA 94704



Fri, 24 May 2002 03:00:00 GMT  
 compilation of

Quote:


> > Why can't you compile closures?
> > (let ((x 1))
> >   (defun dene ()
> >       x))

> I think the reason is implementational.  

> Interpreted and compiled closures may have differing representations
> of the closed-over environment -- typically an interpreted closure
> might have some simple but low performance representation (an alist
> say) whereas a compiled closure might do some much cleverer trick like
> allocating a vector of objects and then compiling references into this
> vector.

But in a somewhat simple Lisp, compiling closures should not be all
that hard.  You have a data structure that contains variable values,
and perhaps even the names of the "closed over" variables; and then
you just think in terms of an imaginary symbol-macrolet "wrapper" that
maps the free variables in the closure's code to the corresponding
data structure references.  [If the env data includes variable names,
you can just put them all in the symbol-macrolet, because lexical
scoping will ensure that only the free ones ever matter.]

Quote:
> Compiling a closure would involve changing the representation of the
> environment from one to the other.

Not necessarily, becuase you can use the interpreter's version as
a data structure (as suggested above).

Quote:
> However, if there is more than one user of the closed-over
> environment, then this is fairly difficult -- the compiler *can't*
> unilaterally change the representation, because the other users may
> still be interpreted.  You can't take a copy of the environment when
> compiling either, because that breaks the program.  And finally, you
> probably can't know who all the other users are and compile them.

But you don't need to do any of those things.

Quote:
> So compiling a closure may be implementationally very hard, and
> therefore the result is left as `undefined' in the standard.

Well, it's certainly something that would require some extra work, and
may make it harder to optimize some things.  The ability to compile
closures is probably not sufficiently valuable.

There may also be something about Common Lisp that makes it much
harder than I've suggested above [hence my "somewhat simple"
qualification].  You can also close over function and block names
(and go tags).  That at least complicates things.  I can't think
of any other factors off hand.

-- j



Sat, 25 May 2002 03:00:00 GMT  
 compilation of


Quote:


>> > Why can't you compile closures?
>> > (let ((x 1))
>> >   (defun dene ()
>> >       x))

>> I think the reason is implementational.  

>> Interpreted and compiled closures may have differing representations
>> of the closed-over environment -- typically an interpreted closure
>> might have some simple but low performance representation (an alist
>> say) whereas a compiled closure might do some much cleverer trick like
>> allocating a vector of objects and then compiling references into this
>> vector.

>But in a somewhat simple Lisp, compiling closures should not be all
>that hard.  You have a data structure that contains variable values,
>and perhaps even the names of the "closed over" variables; and then
>you just think in terms of an imaginary symbol-macrolet "wrapper" that
>maps the free variables in the closure's code to the corresponding
>data structure references.  [If the env data includes variable names,
>you can just put them all in the symbol-macrolet, because lexical
>scoping will ensure that only the free ones ever matter.]

>> Compiling a closure would involve changing the representation of the
>> environment from one to the other.

>Not necessarily, becuase you can use the interpreter's version as
>a data structure (as suggested above).

I ran into problems with this (compiling closures) when I wrote
PowerLisp, which included both the standard integrated compiler and
interpreter. For this and several other reasons, I chose to go with
compiler-only for Corman Lisp. This has been far easier to maintain
and enhance. When you try to support both interpreted and compiled
code you end up with subtle behavi{*filter*}differences if you are not very
careful every step of the way. Areas I found tricky in this regard
included closures, special variable binding, exception-handling,
debugging tools and declaration processing, to name a few.

By the way, I always assumed that the Common Lisp rule against
compiling functions with non-null lexical environments was in
deference to those implementations which could not easily support
this. However, I think it is a pretty ugly limitation of the language,
where you can otherwise treat a function as a function, regardless of
how it was defined. Also, I don't think the standard provides any way
to determine if an interpreted function was defined in a non-null
lexical environment or not.

Roger Corman



Sat, 25 May 2002 03:00:00 GMT  
 compilation of

Is it not a closure compilation?  Does the message mean it stays
interpreted? (Excerpt from LWW 4.1.18.)

CL-USER 225 > (let ((x 8))
                (setf adder (compile nil #'(lambda (y) (+ x y)))))
;;;*** Warning between functions:   The definition supplied, #<closure
SPECIAL::APPLY-INTERPRETED-CLOSURE 20405AAA>, is already compiled.
#<closure SPECIAL::APPLY-INTERPRETED-CLOSURE 20405AAA>

CL-USER 226 > (funcall adder 3)
11

Robert (this is not a return value)



Sat, 25 May 2002 03:00:00 GMT  
 compilation of

Quote:

>By the way, I always assumed that the Common Lisp rule against
>compiling functions with non-null lexical environments was in
>deference to those implementations which could not easily support
>this. However, I think it is a pretty ugly limitation of the language,
>where you can otherwise treat a function as a function, regardless of
>how it was defined. Also, I don't think the standard provides any way
>to determine if an interpreted function was defined in a non-null
>lexical environment or not.

Yes, I think it was a concession to simplify compiler implementations.
However, it wasn't seen as a significant hardship, because of the
expectations about how people deploy software.  In general, programmers
compile files, and that's where functions in non-null environments will be
found, so they'll be compiled.  Functions that need to be compiled at
runtime are generally those that were constructed on the fly by consing up
a lambda expression and coercing it to type FUNCTION, or by passing the
lambda expression as a second argument to COMPILE; these will always be in
a null lexical environment.

Yes, it's possible to do (eval '(defun outer (x) (defun inner ...))), and
then you could conceivably want to compiler INNER without compiling OUTER.
But this unusual combination wasn't considered important enough to require
implementors to go the extra mile to support compiled access to interpreted
environments.

Can someone explain realistic circumstances when it's necessary to compile
lexical closures rather than compiling the surrounding function?

--

GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.



Sun, 26 May 2002 03:00:00 GMT  
 
 [ 25 post ]  Go to page: [1] [2]

 Relevant Pages 

1. Special compilation action for defalut compilation sematics

2. HW compilation vs SW compilation

3. dynamic/adaptive compilation/optimi

4. Compilation messages on Transcript

5. package using pool dictinary compilation failures

6. dynamic compilation of APL

7. byte compilation

8. looking for DJGPP compilation of gawk v3.1.0.1

9. GAWK 3.0.95 - some questions/comments on PC compilation(s)

10. FTWALK: Solaris compilation

11. Vector example compilation

12. Smalltalk Compilation

 

 
Powered by phpBB® Forum Software