Subject: [clisp-list] Re: Lisp question

From: "Hoehle, Joerg-Cyril" <[email-masked]>
Date: Mon Oct 6 01:05:01 2003

Hi,
>2. in general, the standard way is the same as adding lists of 
>numbers &c:
>        (reduce (lambda (s1 s2) (concatenate 'string s1 s2))
>                list-of-strings :initial-value "")
>   (CLISP-specific ext:string-concat is again faster:
>        (reduce #'ext:string-concat list-of-strings)
>   moreover, it does not cons up a lambda).

This is wrong [Sam, was it late night? :)]. Both don't create closure objects ("a lambda") upon each invocation.
CLISP's compiler is very well (and has always been) able to determine that the above lambda expression does not depend on run-time values. It's a function constant.
As a result, it does not cost more than a function call. The constant function object is stored as part of the enclosing function, e.g. foo1, and is created once only during e.g. loading of the containing .fas file.

(defun foo1 (list-of-strings)
(reduce (lambda (s1 s2) (concatenate 'string s1 s2)) list-of-strings :initial-value ""))

(disassemble #'foo1)
Disassembly of function FOO1
(CONST 0) = #<COMPILED-CLOSURE FOO1-1>
(CONST 1) = ""

Other compilers also know this optimization.
That's why it's better (performance-wise), for simple helper functions, to explicitly pass arguments than to close over some, even if it looks like repetition at the source-code level.
E.g. prefer:
(defun foo (a b c)
  (flet ((bar (x y z)
            (code involving only x y z)))
    (bar a (length b) (append a c)))
over:
(defun foo (a b c) ; less performant
  (flet ((bar (x z)
           (code using xyz and a b or c, e.g. (length b))))
    (bar a (append a c))))

Moreover, the local function can be copied as is into another source code, while the one which depends on an outer variable (b) is likely to yield to copy&paste trouble.

(length (times (foo1 list-of-strings)))
                                            Permanent            Temporary
Class                                  instances   bytes    instances   bytes
-----                                  --------- ---------  --------- ---------
SIMPLE-STRING                                  1       500         10      2640
; no FUNCTION object is created
-----                                  --------- ---------  --------- ---------
Total                                          1       500         10      2640

Regards,
	Jorg Hohle

---

From: Sam Steingold <[email-masked]>
Date: Tue Oct 7 08:01:13 2003

> * Hoehle, Joerg-Cyril <[email-masked]> [2003-10-06 10:03:24 +0200]:
>
> This is wrong [Sam, was it late night? :)]. Both don't create closure
> objects ("a lambda") upon each invocation.

I did not say "upon each invocation".
I meant that there are two savings: first, EXT:STRING-CONCAT is faster
than (CONCATENATE 'STRING ...), and, second, it is called directly and
not via an ad hoc lambda.

-- 
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>
Sufficiently advanced stupidity is indistinguishable from malice.