Subject: A short course in LISP, LAMBDA, QUOTE, MAPCAR...
Date: Sat, 02 Nov 1996 08:50:38 -0800
From: Lu <>
Organization: CAD\Tek
Newsgroups: comp.cad.autocad,
Message-ID: <>

Hi All,

Vladimir Nesterovsky kindly sent me the following "short LISP course" explaining the usage of a few commands that I do not even begin to understand. :-)

He has done an excellent job describing the commands and I think after a week of rereading this, It will all sink in.

Thanks Vladimir

Message content follows ;-----------------------------------------------------

On Fri, 01 Nov 1996 23:34:35 -0800 Lu wrote:
>Vladimir Nesterovsky wrote:
>> On Sun, 27 Oct 1996 04:13:05 -0800, - Lu <> wrote
>> >rosie wrote:
>> >> there are 14 paths and 12 pigs.
>> >> How can there be 24 ducks?
>> >This is one way. (I am sure there are many other ways)
>> It may be
>> (defun mult2 ( strng)
>> (strlgather
>> (mapcar
>> '(lambda(s / n)
>> (if(zerop(setq n(atof s)))s
>> (rtos (* n 2))))
>> (strlparse strng " ")) ;; parse by spaces
>> " ")) ;; gather back with spaces
>> Have fun, >
>Thanks. You guys amaze me. :-) I have never taken the time to learn
>the usage of LAMBDA and MAPCAR.

It's really simple. (lambda(x)(* x x)) is just the same as '((x)(* x x)) (note the quote) or (defun temp_func(x)(* x x)). The only difference, I guess, is that it may be virtualized after (vmon), but now at modern times all the memory is virtual anyway (defun will also spoil your name space).

QUOTE is a function that returns its argument UNEVALUATED. When LISP sees ((x)(* x x)) in your code (w/out quote), it tries to evaluate the expression, and whilst it's a list, LISP thinks it's user function call, like (doit 1 2 3). In the latter DOIT is SYMbol that evaluates to list(== user function) and that's OK, but in the former ((x)...) the first argument isn't SYM at all, so you'd get BAD FUNCTION error with this code. LISP want to evaluate everything so before passing it on to MAPCAR, it will evaluate ((x) (* x x)), but (x) is not a function, hence the error.

Now, you don't want to evaluate this right away, only to pass it as argument to MAPCAR (see later), so you use quote to pass it AS IT IS, UNEVALUATED. It's like you've being typing it yourself at keyboard while executing the MAPCAR over and over again.

Now for MAPCAR. It's a function that needs 1. quoted-sym OR quoted-lambda OR quoted-user-function-list 2. some list 3...optional more lists

Let's say we call it with (mapcar 'myfunc mylist) The result will be LIST of RESULTS of calling MYFUNC with each element of MYLIST. For example (defun mysqr(x)(* x x)) (mapcar 'mysqr (list 1 2 3 4)) would return (1 4 9 16) Again MYSQR is quoted here, because MAPCAR is expecting it as such.

MYSQR expects one numeric argument and that's what it gets. If I would call it like (MAPCAR 'MYSQR (list 1 2 "3")) LISP would try to build a list of results like [1] (list (mysqr 1) (mysqr 2) (mysqr "3")) and I would get BAD ARGUMENT TYPE error at "3". Note again that if you'd write this expression [1] yourself, MYSQR is again QUOTED-SYM of previously defined user-function that evaluates to some list, having it's first argument as a list too, so at this point LISP acknowledges such a list as user function and tries to evaluate it, substituting you real arguments for the fake arguments from its arguments-list.

SO if you just want some function to be used in MAPCAR and if you don't want it hanging over not being used anywhere else, you may use LAMBDA. It's a function that creates kind of UNONYMOUS FUNCTION and returns it QUOTED, just like DEFUN do (only creating NAMED function that stays in environment).

MAPCAR is great in that it don't need to know OF HOW MUCH LENGTH a data-list is. It doesn't care. It just runs to the end of it, as at run- time it will be known. So you, at writing-time (like compile-time in compiled languages, like C etc), don't have to know the exact length of your data-list, and IT'S GREAT! It lets you deal with variable-length data easily, and all the real data is such.

So I can (mapcar 'mysqr '(1 2 3)) or I can (mapcar 'mysqr '(1 2 3 4 5)), whatever.

There's something more. Let's say I have this function that SUMs all its arguments. It's a '+, as I may call (+ 1 2) or (+ 1 2 3) etc.

Now when I write (mapcar '+ '(1 2 3) '(4 5 6)) it's equivalent to (list (+ 1 4) (+ 2 5) (+ 3 6)) I can also write (mapcar '+ '(1 2 3)'(4 5 6)'(7 8 9)), equal to (list (+ 1 4 7)(+ 2 5 8)(+ 3 6 9)) etc.

So we have another flexibility here. Of course I am responsible to provide my callable function with the appropriate number of arguments fed by MAPCAR, because else I'll get TOO MANY/FEW ARGUMENTS error when LISP will be eventually evaluating this.

So what I do here, is 1. take a string apart and build a list of 'words' == substrings separated by " " (using my STRLPARSE function == STRing to List PARSE) 2. For each of words apply some function and build up the list of results - that's a MAPCAR 3. Use LAMBDA to make this function. It will try to ATOF every word. If is not convertible, 0.0 will be returned, so I just return it (and it was real 0 there, then if multiplied by some # it will be 0 again), BUT if it's a number, I multiply it by 2 and makes it string again (here DIMZIN and LUPREC will come into place). 4. No I have list of words where each number was mult. by 2. 5. Just gather it back by STRLGATHER using space as a glue string.

Isn't it a simple way of thinking? Forget about all that nasty counters, setq's and so on. Just operate upon your lists of data! Take it apart, apply some function, combine it back - voila! It's all done on new level of operating. The system cares about all this indexing stuff, and you're relieved to do some essential work and creative thinking.

BTW there's some bug in my function. Namely when called with "it's 2 o'clock now" it will return the phrase not exactly as it should. Try to figure out in what way.

(now that I've suddenly being writing THAT much of explanation, would you mind me reposting it on Usenet and forward to some people?)

>A long time ago I had seen a method for autoloading LISP, as follows;
>(IF (/= fun_name NIL)(LOAD "fun_name"))

It's the same thing. Of course it must be (if (= fun_name NIL) (load "fun_file"))

>This does not work for (DEFUN Fun_name() or (DEFUN C:Fun_name().

??? It must do. More simple way to write the same thing would be (if (null fun_name) (load "fun_file")), but fun_name would got evaluated by LISP and to prevent this unnecessary effect, I use (if (not (boundp 'fun_name)) (load "fun_file")).

It's essentially the same, checking if 'fun_name evaluates to NOT NIL, but without evaluating it and passing it on stack, which is superfluous (although harmless -- if you'd write SO BIG function to cause a LISP STACK OVERFLOW here, it wouldn't evaluate anyway, even load, I suspect).

>I am sure yours will;
>(DEFUN Include(gsym fname)
> (IF (NOT(BOUNDP qsym))(LOAD fname))) >
>In the following; I'll do it your way :-)
>(include 'c:mdm "mdmfile")
>What does the ', quote, do? I never understood the reason for it. I am self taught.

Me too ;) BOUNDP expects quoted sym as argument. Without quote, c:mdm would got evaluated and it would end up internally with (boundp ((arg1 arg2)(do_some)) ) and would always return nil.

>PS: I am an old BASIC programmer. My style is to capatilize command names.

Have more fun with LISP, -- Vladimir Nesterovsky self-taught LISP/C/C++ etc. too <> 11/02/96 19:56:48

P.S. If you would set up your mailer to include the e-mail address of those you quote, I would forward this to that misterious Rosie too.

P.P.S. Have you got the great TRANSPOSE from Douglas Wilson's LISP PUZZLE? It's here one more time:

(defun transpose(l)(apply 'mapcar (cons 'list l)))

How does this works? (cons 'list l) returns (list 'list (car l)(cadr l) etc....), then apply calls mapcar with all that's in the list as arguments, (mapcar 'list (car l)(cadr l)...) !!!

end message;-----------------------------------------------------------

If you got this far, It must be a week later :-)

Cheers, Lu //------------------------------------------------------------------ // When all else fails, read the book. // CAD\Tek Home Page: //------------------------------------------------------------------