Subject: [clisp-list] questions

From: "Blake D" <[email-masked]>
Date: Wed Dec 3 10:36:02 2003

Hello,

I am a C++ programmer, new to lisp and clisp, and after looking at the
documentation I still am unclear on a few basic things.

Does clisp compile to byte code instead of native machine code?

How does speed of execution in clisp compare with lisp compilers that
compile to native machine code?

How would I packaged up a clisp application for distribution? In other
words, does it to create a self contained executable, or are applications
run in some other way?

What would be the command to create an application from the source files
a.cl and b.cl?

What kind of file(s) would be generated? Would there be one file or more
than one?

What would be the command to run that application?

Does the clisp license allow me to distribute my commercial applications
with no restrictions?

Does clisp have tail recursion optimization to prevent stack overflows on
deep recursions?

Thank you,
Blake

---

From: Sam Steingold <[email-masked]>
Date: Wed Dec 3 11:44:09 2003

> * Blake D <[email-masked]> [2003-12-03 11:35:46 -0700]:
>

byte code.

> compile to native machine code?

is you are doing lots of floating point computations, you would be
better off with CMUCL.  otherwise, CLISP is fine.

> How would I packaged up a clisp application for distribution?

<http://clisp.cons.org/impnotes/quickstart.html>

> Does the clisp license allow me to distribute my commercial
> applications with no restrictions?

<http://clisp.cons.org/impnotes/app-dev.html>

> Does clisp have tail recursion optimization to prevent stack overflows
> on deep recursions?

no.

-- 
Sam Steingold (http://www.podval.org/~sds) running w2k
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.honestreporting.com>
Don't use force -- get a bigger hammer.

---

From: "John K. Hinsdale" <[email-masked]>
Date: Wed Dec 3 12:09:01 2003

> documentation I still am unclear on a few basic things.

I'm sure you'll get lots of response to this, but you'll probably also
benefit from diversity of opinions

 > Does clisp compile to byte code instead of native machine code?

byte code, no native

 > How does speed of execution in clisp compare with lisp compilers
 > that compile to native machine code?

Really depends on what you are doing.  The general answer of course is
that a native-compiling Lisp is going to be faster.  However, in many
cases you will find that Lisp is not the bottleneck; for example I
write Oracle database apps using a C library that is interfaced to
Lisp (where I do some reporting, stats and anlysis).  Most of the
bottleneck is in the database query and access, and all of that is in
C.  The reporting functionality -- for which the programming power of
Lisp is invaluable -- nonetheless does not consume a lot (in terms of
PERCENTAGE of overall CPU used) of resources.

See http://www.cliki.net/Performance%20Benchmarks for some benchmarks.

 > words, does it to create a self contained executable, or are
 > applications run in some other way?

As far as I know, to ship a binary application (assuming your customer
cannot be coutned on to already have CLISP installed) you have to ship
TWO things

  - a binary for the CLISP interpreter (including any extra
    modules that are required)
  - your application code, optinally compiled into .FAS file

See http://clisp.cons.org/impnotes/quickstart.html

 > What would be the command to create an application from the source
 > files a.cl and b.cl?

The docs (above) suggest concatenating all the lisp code into one
file, but I just make a top-level file that calls LOAD on all the
seprate Lisp files that make up my app, then add as the first
line the Unix interpreter directive

	#!/usr/local/bin/clisp -q /path/to/toplevel.lisp

where toplevel.lisp is a small file that has lines like:

	  ; Set load path
          (map 'list (lambda (p) (push p *load-paths*))
	     (reverse '(
	                "/first/dir/to/look"
	                "/next/dir/to/look"
	                )))

	; Load individual files
	(eval-when
	 (:compile-toplevel :load-toplevel :execute)
	 (mapcar #'load
	         '("some-module"
	           "another-module")))

	; Call the top-level function to do something

 > What kind of file(s) would be generated? Would there be one file or
 > more than one?

As above (and I might be wrong here), you would need a whole bunch of
files for the CLISP environment, and then your app could be a single
concatenated file, or a collection of them that are loaded in by a
top-level script (which is my practice).

 > What would be the command to run that application?

In Unix, you create a top-level script, with the name of
your choice, and then just run that script.  This is using
the approach of the "#!" interpreter line.

 > applications with no restrictions?

See http://clisp.cons.org/impnotes/app-dev.html

I am not a lawyer, but my interpretation of the above page is:

Yes, you can distribute your commercial app w/out restriction as long
as your app is not compiled into CLISP itself (which might be the case
if you have modules in "C").  I.e., as long as your commercial app
consists of separate Lisp code (either in source form, or compiled
into un-intelligble .FAS files), then there are no restrictions on the
part of the "application" that consists of your own code.  But since
you would also be distributing a CLISP binary you are of course
subject to the restrictions imposed by CLISP's license.

So (and CLISP developers please correct me if I am wrong), you could,
if you wanted, distribute a commercial CLISP-based app, without
divulging the source, by distributing the CLISP binary, together with
your application compiled into .FAS files.

All that said, I would suggest you consider the advantages of
distributing your app as free software (note that that makes it no
less of a "commercial" app).  See
http://www.gnu.org/gnu/thegnuproject.html for some good arguments.

 > Does clisp have tail recursion optimization to prevent stack
 > overflows on deep recursions?

I'm not sure.  The function below gives me a seg. fault when I call it
with N larger than 1764 ...

	(defun factorial (n)
	  (if (<= n 2)
	      n
	    (* n (factorial (- n 1)))))

Shouldnt' this use only a little stack?

Hope this helps.

---

From: Pascal J.Bourguignon <[email-masked]>
Date: Wed Dec 3 12:29:05 2003

> Does clisp have tail recursion optimization to prevent stack overflows on

It does seem to do it, but there are other limitations of course:

[1]> 
[2]>  (defun fact (x &optional (r 1)) (if (<= x 1) r (fact (1- x) (* x r))))
FACT
[9]> (compile 'fact)
FACT ;
NIL ;
NIL
[10]> (fact (fact 10))
*** - overflow during multiplication of large numbers
1. Break [11]> :bt
EVAL frame for form (FACT (FACT 10))
Printed 0 frames
1. Break [11]> :bt4
EVAL frame for form (FACT (FACT 10))
Printed 0 frames
1. Break [11]> :bt3
frame binding variables (~ = dynamically):
  | ~ SYSTEM::*PRIN-STREAM* <--> #<UNBOUND>
frame binding variables (~ = dynamically):
  | ~ *PRINT-READABLY* <--> NIL
frame binding variables (~ = dynamically):
  | ~ *PRINT-ESCAPE* <--> T
Printed 2 frames
1. Break [11]> 

-- 
__Pascal_Bourguignon__                          http://www.informatimago.com/
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Living free in Alaska or in Siberia, a grizzli's life expectancy is 35 years,
but no more than 8 years in captivity.           http://www.theadvocates.org/

---

From: Pascal J.Bourguignon <[email-masked]>
Date: Wed Dec 3 12:38:04 2003

> Shouldnt' this use only a little stack?

You have a problem:

[21]> (time (factorial 10000))
Real time: 1.986322 sec.
Run time: 1.81 sec.
Space: 69640484 Bytes
GC: 34, GC time: 1.38 sec.

---

From: zera holladay <[email-masked]>
Date: Wed Dec 3 15:04:03 2003

What about?

(defun factorial (n)
  (do ((j n (- j 1))
       (f 1 (* j f)))
      ((= j 0) f)))

Or is the point to test something we would not do or
would never be practical?  

Further, I also don't think the recursive version of 

 	(defun factorial (n)
 	  (if (<= n 2)
 	      n

is a tail recursive function since the (* n (fact... )
function is pending after the recursive calls return. 
I tried a few painful tail recursive functions for
factorial, but after a while I had to ask  myself why
I was doing this.

-zh

--- "Pascal J.Bourguignon" <[email-masked]>
> GC: 34, GC time: 1.38 sec.

__________________________________
Do you Yahoo!?
Free Pop-Up Blocker - Get it now
http://companion.yahoo.com/

---

From: Marco Antoniotti <[email-masked]>
Date: Wed Dec 3 15:20:02 2003

(defun fact-tail-recursive (x &optional (acc 1))
    (if (zerop x)
        acc
        (fact-tail-recursive (1- x) (* x acc))))

On Wednesday, Dec 3, 2003, at 18:03 America/New_York, zera holladay 
wrote:

> -------------------------------------------------------
> This SF.net email is sponsored by OSDN's Audience Survey.
> Help shape OSDN's sites and tell us what you think. Take this
> five minute survey and you could win a $250 Gift Certificate.
> http://www.wrgsurveys.com/2003/osdntech03.php?site=8
> _______________________________________________
> clisp-list mailing list
> [email-masked]
> https://lists.sourceforge.net/lists/listinfo/clisp-list
>
--
Marco Antoniotti
NYU Courant Bioinformatics Group		tel. +1 - 212 - 998 3488
715 Broadway 10th FL				fax. +1 - 212 - 998 3484
New York, NY, 10003, U.S.A.

---

From: "Steven E. Harris" <[email-masked]>
Date: Thu Dec 4 07:58:04 2003

> 	#!/usr/local/bin/clisp -q /path/to/toplevel.lisp

You can also load your code into CLISP, dump an image
(ext:saveinitmem), then load that image at startup with the -M
command-line option. Then all your startup program has to do is call
on some other function loaded as part of the saved image, possibly
after inspecting some command-line arguments.

Your user-visible "program" could then look like:

,----
| #!/usr/local/bin/clisp -norc -M lispinit.mem
| 
| (do-it)
| (ext:exit)
`----

-- 
Steven E. Harris        :: [email-masked]
Raytheon                :: http://www.raytheon.com

---

From: Sam Steingold <[email-masked]>
Date: Thu Dec 4 09:33:03 2003

> * Steven E. Harris <[email-masked]> [2003-12-04 07:54:53 -0800]:
>

EXIT is not needed - script exits when the file ends

you can just create an alias to

/usr/local/bin/clisp -norc -M lispinit.mem -x '(do-it)'

moreover, you can make you image run DO-IT on startup (see
<http://clisp.cons.org/impnotes/p-indep.html#image>) and then "clisp -M
lispinit.mem" will run your stuff.

-- 
Sam Steingold (http://www.podval.org/~sds) running w2k
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.honestreporting.com>
If you want it done right, you have to do it yourself

---

From: Szymon <[email-masked]>
Date: Thu Dec 4 09:37:08 2003

Hi.

> > Does clisp have tail recursion optimization to prevent stack overflows

why ?

regards, szymon.

---

From: "Steven E. Harris" <[email-masked]>
Date: Thu Dec 4 10:01:01 2003

> EXIT is not needed - script exits when the file ends

Ah, I see. My mistake, per below.

> /usr/local/bin/clisp -norc -M lispinit.mem -x '(do-it)'

Yes, for very simple scripts like this one. I was cheating with my
example, though. My startup script is actually about ten lines
long. It's stuff that I didn't feel like building into the image as I
toyed with the user interface of the script.

> <http://clisp.cons.org/impnotes/p-indep.html#image>) and then "clisp
> -M lispinit.mem" will run your stuff.

Yes, I have experimented with the :INIT-FUNCTION argument to
EXT:SAVEINITMEM. That must have been where I picked up the use of the
EXT:EXIT function being required at the end.

I found that using this feature was limiting. My scenario: build a
single image with as a "library" or union of functionality, with lots
of little startup scripts each calling some different "application"
entry point in that image. I guess one could do the same thing by
having the :INIT-FUNCTION check which command name was invoked on the
command-line and decide what to do from there.

There's enough flexibility in there to do the same job in many
ways. It's a great system.

---

From: Sam Steingold <[email-masked]>
Date: Thu Dec 4 10:43:01 2003

> * Szymon <[email-masked]> [2003-12-04 18:35:57 +0100]:
>
debuggability

-- 
Sam Steingold (http://www.podval.org/~sds) running w2k
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.honestreporting.com>
Every day above ground is a good day.

---

From: Szymon <[email-masked]>
Date: Thu Dec 4 11:30:02 2003

Hi.
> >> > Does clisp have tail recursion optimization to prevent stack overflows
"no" ---> both interpreted & compiled code?
> debuggability
Thanks.

Does compilation (in clisp) transform tail-recursion to loops?  For
example: before compilation I can execute tail-rec fuction ~3000
times (clisp -m2MB), after compile '... 30000+ (no time to test it
longer).

regards, szymon.

---

From: Sam Steingold <[email-masked]>
Date: Thu Dec 4 12:37:02 2003

> * Szymon <[email-masked]> [2003-12-04 20:28:49 +0100]:
>
yes.

>> > why ?
>> debuggability
> Thanks.
>
> Does compilation (in clisp) transform tail-recursion to loops?

no.  patches that optionally optimize tail calls (not necessarily
recursive) are welcome.

> For example: before compilation I can execute tail-rec fuction ~3000

compiled code uses less stack.

-- 
Sam Steingold (http://www.podval.org/~sds) running w2k
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.honestreporting.com>
The difference between genius and stupidity is that genius has its limits.

---

From: Pascal J.Bourguignon <[email-masked]>
Date: Thu Dec 4 13:54:02 2003

> compiled code uses less stack.

I'm  sorry  Sam but  you're  wrong.  CLISP  reduces tail-recursion  in
compiled code:

[31]> (defun fact (n &optional (r 1)) (if (> n 1) (fact (1- n) (* r n)) r))
FACT
[32]> (disassemble 'fact)

Disassembly of function FACT
(CONST 0) = 1
1 required argument
1 optional argument
No rest parameter
No keyword parameters
16 byte-code instructions:
0     L0
0     (JMPIFBOUNDP 1 L5)
3     (CONST 0)                           ; 1
4     (STORE 1)
5     L5
5     (LOAD&PUSH 2)
6     (CONST&PUSH 0)                      ; 1
7     (CALLSR&JMPIF 1 49 L14)             ; >
11    (LOAD 1)
12    (SKIP&RET 3)
14    L14
14    (LOAD&DEC&PUSH 2)
16    (LOAD&PUSH 2)
17    (LOAD&PUSH 4)
18    (CALLSR&PUSH 2 56)                  ; *
21    (JMPTAIL 2 5 L0)  <========================= HERE ===================
#<COMPILED-CLOSURE FACT>

[35]> (defun fact2 (n &optional (r 1)) 
          (cond ((<= n 1) r) 
                ((evenp n) (fact2 (- n 2) (* r n (1- n)))) 
                (t         (fact2 (1- n)  (* r n)))))
FACT2
[36]> (disassemble 'fact2)

Disassembly of function FACT2
(CONST 0) = 1
(CONST 1) = -2
1 required argument
1 optional argument
No rest parameter
No keyword parameters
27 byte-code instructions:
0     L0
0     (JMPIFBOUNDP 1 L5)
3     (CONST 0)                           ; 1
4     (STORE 1)
5     L5
5     (LOAD&PUSH 2)
6     (CONST&PUSH 0)                      ; 1
7     (CALLSR&JMPIF 1 50 L26)             ; <=
11    (LOAD&PUSH 2)
12    (CALLS2&JMPIF 148 L29)              ; EVENP
15    (LOAD&DEC&PUSH 2)
17    (LOAD&PUSH 2)
18    (LOAD&PUSH 4)
19    (CALLSR&PUSH 2 56)                  ; *
22    (JMPTAIL 2 5 L0)  <========================= HERE ===================
26    L26
26    (LOAD 1)
27    (SKIP&RET 3)
29    L29
29    (CONST&PUSH 1)                      ; -2
30    (LOAD&PUSH 3)
31    (CALLSR&PUSH 2 54)                  ; +
34    (LOAD&PUSH 2)
35    (LOAD&PUSH 4)
36    (LOAD&DEC&PUSH 5)
38    (CALLSR&PUSH 3 56)                  ; *
41    (JMPTAIL 2 5 L0)  <========================= HERE ===================
#<COMPILED-CLOSURE FACT2>

Why do you think there is a JMPTAIL instruction in the virtual machine?

---

From: Sam Steingold <[email-masked]>
Date: Thu Dec 4 14:09:01 2003

> * Pascal J.Bourguignon <[email-masked]> [2003-12-04 22:52:55 +0100]:
>

good.  I mis-remembered.
So CLISP does eliminate tail-recursion, but not tail calls.

thanks for correcting me.

-- 
Sam Steingold (http://www.podval.org/~sds) running w2k
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.honestreporting.com>
Someone has changed your life.  Save? (y/n)