I want lambda more clear

Discussion in 'AutoCAD' started by Adesu, Nov 26, 2004.

  1. Adesu

    Adesu Guest

    For beginner autolisp programmer,as like me ,lambda is a function to become
    "headache",now I want more clear with lambda,because lambda can't work
    without added others (as mapcar and apply),different with mapcar more easy
    to learn it ,it can work alone,here below
    _$ (mapcar '1+ (list 10 20 30)) ===> this is simple and easy to
    understand
    (11 21 31)

    On AutoCAD help;
    Lambda is Defines an anonymous function
    format formula;
    (lambda arguments expr... lst)

    _$ (apply '(lambda (x y z)(* x (- y z)))'(5 20 14))

    30

    Discribtion for formula above

    20 - 14 = 6 and then
    6 x 5 = 30

    argument => (x y z)
    expr...) => (* x (- y z))
    lst => '(5 20 14)

    Is it true ? any comment ?
     
    Adesu, Nov 26, 2004
    #1
  2. Hi again.


    --

    Marc'Antonio Alessi
    http://xoomer.virgilio.it/alessi
    (strcat "NOT a " (substr (ver) 8 4) " guru.")

    --

    --------------------------------------------------------------------------------

    cadd infinitum • AutoLISP • Mapcar


    --------------------------------------------------------------------------------

    "Mapcar discussion" • Copyright © 1999 • Michael Puckett • All rights
    reserved


    --------------------------------------------------------------------------------

    Bookmarks:

    Introduction
    Apply
    Mapcar
    Lambda
    Practicum
    Download
    Copyright


    --------------------------------------------------------------------------------


    Introduction

    Numerous articles have been written about the AutoLISP mapcar function.
    Many provide excellent technical content but still leave the reader
    wondering "how will this make my code more efficient"? This paper will
    concentrate more on simple mapcar examples in a somewhat conversational
    manner, rather than an exhaustive "what is mapcar" type of discussion.

    Any discussion of mapcar warrants a brief foray into the apply function, as
    they make a powerful arsenal when used together, thus, that is where I'll
    start.


    --------------------------------------------------------------------------------


    APPLY

    The apply function is a very useful function that is often used in
    conjunction with mapcar. Yet, because its association with mapcar, the
    assumption is that it doesn't "stand on its own". Indeed, my introduction
    draws a connection between the two as well, so I need to put it into
    perspective here - while they work very well in concert, there are many uses
    for the apply function that have nothing to do with mapcar. However,
    understanding the apply function will help you exploit it, particularly when
    used with mapcar.

    The AutoLISP on line help sports brevity in its definition of apply, and
    states "Passes a list of arguments to a specified function", then goes on to
    say "works with built in functions as well as user defined ones". While
    this description is perfectly adequate for the reasonably experienced
    programmer, it may leave a newbie scratching his or her respective head.

    I find examples the most illuminating so here we go ...

    Assume we have a number of integers, 8 2 5 1 14 4 5 3 and we want to find
    the largest one. Normally you would use the max function, which takes
    numbers as its arguments:

    (max 8 2 5 1 14 4 5 3) 14

    Which returns 14 (shown above as 14, the convention used for the balance of
    this document).

    This is fine, but what if the integers are stored in a list?

    e.g.

    (setq ints '(8 2 5 1 14 4 5 3))

    How would you use the max function with a list, since it takes numbers, not
    lists as arguments?

    You cannot use ...

    (max ints)

    Wrong, bad argument type.

    but you can use ...

    (apply 'max ints) 14

    Notice that max is quoted. If we did not quote it would be evaluated
    immediately. We want max to be taken literally. Normally you will quote
    functions used with apply (be them built in or user defined).

    If you are familiar with the eval and cons functions it would be equivalent
    to:

    (eval (cons 'max ints)) 14

    or (using eval and append) ...

    (eval (append '(max) ints)) 14

    or (using eval, append and list) ...

    (eval (append (list 'max) ints)) 14

    Obviously apply is more elegant and succinct.

    Let's explore some more examples (remember the variable 'ints' is set to '(8
    2 5 1 14 4 5 3)) ...

    (apply 'min ints) 1
    (apply '+ ints) 42
    (apply '* ints) 67200

    Determine if all members of a list are not nil ...

    (apply 'and '(1 2 3 nil 5 6 7)) nil
    (apply 'and '(1 2 3 4 5 6 7)) t

    Determine if any members of a list are not nil ...

    (apply 'or '(nil nil 3 nil nil)) t

    Concatenate a list of strings ...

    (apply 'strcat '("A" "B" "C")) "ABC"

    As you can see, apply is a very useful function. When you harness the power
    of mapcar and apply together you can do a surprising amount of work with a
    rather nominal amount of code, which leads us to the mapcar discussion.


    --------------------------------------------------------------------------------


    MAPCAR

    The mapcar function is described in the AutoLISP online help as "Returns a
    list of the result of executing a function with the individual elements of a
    list or lists supplied as arguments to the function". I like this
    definition. But perhaps a brief example would be illuminating:

    (mapcar 'strcase '("a" "b")) ("A" "B")

    Notice that strcase is quoted. If we did not quote it would be evaluated
    immediately. We want strcase to be taken literally. Normally you will
    quote functions used with mapcar (be them built in or user defined).

    Cool, how'd it do that?

    If you consider the mapcar definition above, functionally this is what
    happens ...

    (list (strcase "a") (strcase "b")) ("A" "B")

    or ...

    (setq temp nil)
    (foreach x '("a" "b")
    (setq temp (append temp (list (strcase x))))
    )
    ; temp ("A" "B")

    or ...

    (setq temp nil)
    (foreach x '("a" "b")
    (setq temp (cons (strcase x) temp))
    )
    (setq temp (reverse temp))
    ; temp ("A" "B")

    Wow, that replaces a lot of code; elegant and efficient.

    Now then, on to some more short examples ...

    (mapcar 'rtos '(3.14159 1.60803)) ("3.14" "1.61")

    Output of above depends on your system settings.

    (mapcar 'read '("x" "y" "z")) (X Y Z)

    (mapcar '+ '(1 2 3) '(4 5 6)) (5 7 9)

    Wait a second, what's with the last example?

    One of the flexible things about mapcar is that when passed more than one
    list, it will attempt to 'map' the list elements as arguments to the
    supplied function. What? Let's look at the previous example ...

    (mapcar '+ '(1 2 3) '(4 5 6)) (5 7 9)

    Functionally this is what happens ...

    (list (+ 1 4)(+ 2 5)(+ 3 6)) (5 7 9)

    This can lead to some interesting code ...

    (mapcar 'set '(x y) '(2 4))

    'set is not a typo.

    Which equates to ...

    (list
    (set 'x 2)
    (set 'y 4)
    )

    or ...

    (list
    (setq x 2)
    (setq y 4)
    )

    While a value is returned (2 4), we really don't care in this instance.
    What we do care about is that variables 'x' and 'y' have been set to 2 and 4
    respectively. So what. Wouldn't it be easier to just do separate (setq x
    2) (setq y 4) calls? Sure. But often there is a need to assign separate
    list elements to variables. Consider the 3D point - often it is desirous to
    assign the x, y and z values to ... well x, y and z variables ...

    Assuming p1 = '(10.0 20.0 30.0) ...

    (mapcar 'set '(x y z) p1)

    Now x = 10.0, y = 20.0, z = 30.0

    I think this is more efficient than ...

    (setq
    x (car p1)
    y (cadr p1)
    z (caddr p1)
    )

    Many more examples could be provided for mapcar, but now I'd like to discuss
    lambda, the anonymous function.


    --------------------------------------------------------------------------------


    LAMBDA

    The lambda function simply defines an anonymous function (one without a
    name) right where you need it. Generally this makes code more obvious,
    eliminates the overhead associated with a formally defined function and
    eliminates external dependencies.

    The general syntax of lambda is the same as defun, except no name is
    specified for the function, and generally the entire lambda statement is
    quoted so it won't be evaluated until needed ...

    Defun ...

    (defun name (param1 param2 / local1 local2)
    ...
    [processing]
    ...
    return_value
    )

    Lambda ...

    (lambda (param1 param2 / local1 local2)
    ...
    [processing]
    ...
    return_value
    )

    Even some seasoned programmers aren't aware you can have local variables in
    a lambda defined function.

    Many examples just are confusing, or aren't lucid enough to appreciate what
    this means, or why it would be of any use. So let's employ a short example,
    using one from our apply discussion. Recall the example ...

    (apply 'strcat '("A" "B" "C")) "ABC"

    What if we wanted to separate the individual strings with commas (,) so the
    value returned would be "A,B,C"?

    Let's not use lambda yet, but create a function that takes a string and
    returns it prefixed with a comma ...

    (defun prefix_with_comma (str)
    (strcat "," str)
    )

    Simple enough, now throw it at mapcar ...

    (mapcar
    'prefix_with_comma
    '("A" "B" "C")
    )

    (",A" ",B" ",C")

    Wait, the first item shouldn't be prefixed should it? No. Let's fix it
    then.

    (cons
    (car '("A" "B" "C"))
    (mapcar
    'prefix_with_comma
    (cdr '("A" "B" "C"))
    )
    )

    ("A" ",B" ",C")

    Simple enough, now pass it to the previous apply code ...

    (apply
    'strcat
    (cons
    (car '("A" "B" "C"))
    (mapcar
    'prefix_with_comma
    (cdr '("A" "B" "C"))
    )
    )
    )

    "A,B,C"

    Well that seems to work, but a function to simply add a leading comma?
    Doesn't seem very efficient. Also, the code is now dependent on an
    externally defined function, so it is not generic and cannot be used without
    the prefix_with_comma function loaded in memory. What if we use lambda
    instead? ...

    (apply
    'strcat
    (cons
    (car '("A" "B" "C"))
    (mapcar
    '(lambda (x) (strcat "," x))
    (cdr '("A" "B" "C"))
    )
    )
    )

    "A,B,C"

    All right. Now if we wrap this all up in a defun and parameterize it we
    have a useful little routine (as long as we pass it a list of strings -
    we'll remedy that shortcoming later) ...

    (defun list->str (lst delimeter)
    (apply
    'strcat
    (cons
    (car lst)
    (mapcar
    '(lambda (x) (strcat delimeter x))
    (cdr lst)
    )
    )
    )
    )

    (list->str '("A" "B" "C") ",") "A,B,C"

    Everything is defined right where we need it, no overhead and no external
    dependencies.

    That was easy wasn't it?

    Let's build some real useful functions now with this new found expertise.


    --------------------------------------------------------------------------------


    Practicum

    Building on the preceding information, let's build the following functions:

    · list to comma delimited values (list->cdv list_var)
    · list to space delimited values (list->sdv list_var)

    And the antithesis functions ...

    · comma delimited values to list (cdv->list string_var)
    · space delimited values to list (sdv->list string_var)

    General functions the above are built upon:

    · trim (trim string_var)
    · value to string (val->str value_var)
    · string to value (str->val string_var)
    · list to str (list->str list_var delimeter)

    Any apply, mapcar, lambda code will be highlighted in red, user defined
    functions in magenta.

    These functions will be particularly useful for file I/O, and are available
    for download in one file by clicking here .

    Since the trim, val->str and str->val functions are required by our primary
    functions, I'll pen them first.

    ;|_________________________________________________

    trim
    _________________________________________________

    Trim leading/trailing white space.

    Example ...

    (trim " string ") -> "string"
    _________________________________________________|;

    (defun trim (str / i)
    (cond
    ( (eq 0 (setq i (strlen str))) str)
    ( (< (ascii str) 33)
    (trim (substr str 2))
    )
    ( (< (ascii (substr str i)) 33)
    (trim (substr str 1 (1- i)))
    )
    ( t str )
    )
    )

    ;|_________________________________________________

    val->str
    _________________________________________________

    Convert any value to its string equivalent.

    Examples ...

    (val->str 5) -> "5"
    (val->str 5.0) -> "5.0"
    (val->str '(1.0 2 3)) -> "(1.0 2 3)"
    (val->str '((1.0) 2 3)) -> "((1.0) 2 3)"
    (mapcar 'val->str '(1.0 2 3)) -> ("1.0" "2" "3")
    _________________________________________________|;

    (defun val->str (val / typ var rtn tmp hdl)
    (cond
    ( (null val) "nil")
    ( (eq 'str (setq typ (type val))) val)
    ( (eq 'int typ) (itoa val))
    ( (eq 'real typ)
    (setq var (getvar "dimzin"))
    (setvar "dimzin" 8)
    (setq rtn (rtos val 2 15))
    (setvar "dimzin" var)
    (if (null (wcmatch rtn "*`.*"))
    (strcat rtn ".0")
    rtn
    )
    )
    ( (eq 'list typ)
    (setq rtn (mapcar 'val->str val))
    (apply 'strcat
    (append
    '("(")
    (cons
    (car rtn)
    (mapcar
    '(lambda (x) (strcat " " x))
    (cdr rtn)
    )
    )
    '(")")
    )
    )
    )
    ( t
    (setq
    rtn "<unknown>"
    tmp (strcat (getvar "tempprefix") "val2str.tmp")
    )
    (cond
    ( (setq hdl (open tmp "w"))
    (prin1 val hdl)
    (setq hdl (close hdl))
    (if (setq hdl (open tmp "r"))
    (setq rtn (read-line hdl) hdl (close hdl))
    )
    )
    )
    rtn
    )
    )
    )

    ;|_________________________________________________

    str->val
    _________________________________________________

    Convert a string to a value if appropriate.

    Examples ...

    (str->value "5") -> 5
    (str->value "5.0") -> 5.0
    (str->value "(1 2 3.0)") -> (1 2 3.0)
    _________________________________________________|;

    (defun str->val (str / rtn)
    (cond
    ( (eq 'str (type str))
    (setq red (read str) typ (type red))
    (cond
    ( (eq 'nil typ) nil)
    ( (eq 'sym typ) str)
    ( (eq 'list typ) red)
    ( (eq 'real typ) red)
    ( (eq 'int typ)
    (cond
    ( (wcmatch str "*`'`-*`.*\"")
    (distof str 3)
    )
    ( (wcmatch str "*`'*,*`'*/*")
    (distof str 4)
    )
    ( (wcmatch str "*`/*")
    (distof str 5)
    )
    ( (wcmatch str "*`.*")
    (distof str 2)
    )
    ( t
    (atoi str)
    )
    )
    )
    ( t str ) ; what would you do?
    )
    )
    ( t str )
    )
    )

    ;|_________________________________________________

    cdv->list
    _________________________________________________

    Convert a comma delimited string to a list.

    Example ...

    (cdv->list "1,2,,4.0") -> ("1" "2" nil "4.0")
    _________________________________________________|;

    (defun cdv->list (str / i c w r)
    (setq i 0 w "" str (trim str))
    (repeat (strlen str)
    (setq c (substr str (setq i (1+ i)) 1))
    (if (eq "," c)
    (setq r (cons (trim w) r) w "")
    (setq w (strcat w c))
    )
    )
    (mapcar
    '(lambda (x) (if (eq "" x) nil x))
    (if (eq "" w)
    (reverse r)
    (reverse (cons (trim w) r))
    )
    )
    )

    ;|_________________________________________________

    sdv->list
    _________________________________________________

    Convert a space delimited string to a list.

    Example ...

    (sdv->list "1 2 3.0") -> ("1" "2" "3.0")
    _________________________________________________|;

    (defun sdv->list (str / i c w r)
    (setq i 0 w "" str (trim str))
    (repeat (strlen str)
    (setq c (substr str (setq i (1+ i)) 1))
    (if (eq " " c)
    (if (/= w "") (setq r (cons w r) w ""))
    (setq w (strcat w c))
    )
    )
    (if (eq "" w) (reverse r) (reverse (cons w r)))
    )

    ;|_________________________________________________

    list->str
    _________________________________________________

    Convert a list to delimited (specified) string.

    Examples ...

    (list->str '("1" "2" "3.0") ",") -> "1,2,3.0"
    (list->str '(1 2 3.0) ",") -> "1,2,3.0"
    (list->str '(1 2 3.0) " ") -> "1 2 3.0"
    (list->str '(1 2 3.0) ", ") -> "1, 2, 3.0"
    _________________________________________________|;

    (defun list->str (lst delim)
    (apply
    'strcat
    (cons
    (val->str (car lst))
    (mapcar
    '(lambda (x) (strcat delim x))
    (mapcar 'val->str (cdr lst))
    )
    )
    )
    )

    ;|_________________________________________________

    list->cdv
    _________________________________________________

    Convert a list to comma delimited string.

    Example ...

    (list->cdv '("1" "2" "3.0")) -> "1,2,3.0"
    _________________________________________________|;

    (defun list->cdv (lst)
    (list->str lst ",")
    )

    ;|_________________________________________________

    list->sdv
    _________________________________________________

    Convert a list to space delimited string.

    Example ...

    (list->sdv '("1" "2" "3.0")) -> "1 2 3.0"
    _________________________________________________|;

    (defun list->sdv (lst)
    (list->str lst " ")
    )


    --------------------------------------------------------------------------------


    Using these functions ...

    <to follow>


    --------------------------------------------------------------------------------


    Download

    Click here to download a file containing all the functions defined on this
    page.


    --------------------------------------------------------------------------------

    End Mapcar discussion


    --------------------------------------------------------------------------------

    Was this helpful? Was it clear? Were the examples adequate?

    Let me know: .


    --------------------------------------------------------------------------------

    "Mapcar discussion" • Copyright © 1999 • Michael Puckett • All rights
    reserved.

    You are free to use this document and/or program for personal use, but it is
    a copyrighted work and is not public domain. You may not sell, lease, or
    distribute this document and/or program on any media, including disk, CD or
    electronic means such as, but not limited to, electronic mail (email). You
    may not post this document and/or program online (including web and ftp
    sites, bulletin boards, and any other "online" services) for public viewing
    or download, and you may not publish them in print for public viewing
    without prior written consent of Michael Puckett. Permission to copy,
    distribute or reproduce this document and/or program may be obtained by
    sending a request to the author Michael Puckett at .
    If linking to this site please use http://www.cadvision.com/puckettm, and no
    links to pages herein, because I frequently change them! Thank you :)


    --------------------------------------------------------------------------------

    AutoCAD and AutoLISP are trademarks of Autodesk Inc.


    --------------------------------------------------------------------------------

    cadd infinitum • Copyright © 1997 - 2000 • Michael Puckett • All Rights
    Reserved

    --------------------------------------------------------------------------------
     
    Marc'Antonio Alessi, Nov 26, 2004
    #2
  3. Sorry, I do not have read very well the final note:

    "You may not post this document and/or program online (including web and ftp
    sites, bulletin boards, and any other "online" services) for public viewing
    or download, and you may not publish them in print for public viewing
    without prior written consent of Michael Puckett."

    Anne, can you please delete my previous message?

    Thanks.

    -

    My apologies to Michael Puckett.


    Marc'Antonio Alessi
     
    Marc'Antonio Alessi, Nov 26, 2004
    #3
  4. Adesu

    David Kozina Guest

    Marc,

    While I appreciated the info, I hope MP gave you permission, as per the 2nd
    to the last parragraph.

    Regards,
    David Kozina
     
    David Kozina, Nov 26, 2004
    #4
  5. Adesu

    David Kozina Guest

    Marc,
    I see you can disregard my last post too. :)
     
    David Kozina, Nov 26, 2004
    #5
  6. Marc'Antonio Alessi, Nov 26, 2004
    #6
  7. Marc'Antonio Alessi, Nov 26, 2004
    #7
  8. Adesu

    Anne Brown Guest

    Per his request, this post was removed as the lisp was copyright.
    Thanks Marc for being so responsible when you noticed the posting
    error.

    Subject:
    Re: I want lambda more clear
    Date:
    Fri, 26 Nov 2004 06:57:00 +0100
    From:
    "Marc'Antonio Alessi" <nospam maalessi at tin dot it>
    Newsgroups:
    autodesk.autocad.customization
     
    Anne Brown, Nov 26, 2004
    #8
  9. Thanks Anne,

    and sorry Michael.
     
    Marc'Antonio Alessi, Nov 27, 2004
    #9
  10. Adesu

    Adesu Guest

    Hi Marc ,thanks a lot for your tutorial.
     
    Adesu, Nov 29, 2004
    #10
  11. Adesu

    Joshua Tapp Guest

    Ahhh!!!! Anne!!!!

    I'm sure Michael doesn't mind so much, but we'll let him make that
    call......
     
    Joshua Tapp, Nov 29, 2004
    #11
  12. Adesu

    Doug Broad Guest

    Adesu,

    Are you aware of what you are doing? Are you reading the
    thread? Don't quote back a message that Anne has deleted!

    In even the best cases, you should never quote back such
    a large reply.
     
    Doug Broad, Nov 29, 2004
    #12
  13. Adesu

    Adesu Guest

    Hi Doug, sorry
     
    Adesu, Nov 29, 2004
    #13
  14. Anne,

    I have informed Michael P. (he already knew it) and him had way
    of seeing that the message has been erased.

    I think that is better to remove the whole discussion for the new
    answer of Adesu (11-29-2004 2.36).


    Thanks and sorry again.


    --

    Marc'Antonio Alessi
    http://xoomer.virgilio.it/alessi
    (strcat "NOT a " (substr (ver) 8 4) " guru.")

    --
     
    Marc'Antonio Alessi, Nov 29, 2004
    #14
  15. Adesu

    BillZ Guest

    Lambda is Defines an anonymous function
    <<

    And add this:

    Use the lambda function when the overhead of defining a new function is not justified.

    ============

    Seems to imply a memory savings of (?) a namespace?

    Bill
     
    BillZ, Nov 29, 2004
    #15
  16. Adesu

    Anne Brown Guest

    Already removed earlier this morning. If you are using a
    discussion group reader, clear the cache and all the deleted
    messages will not show anymore.

    Anne
     
    Anne Brown, Nov 29, 2004
    #16
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.