Reu Posted February 1, 2013 Posted February 1, 2013 Is there a logical reason for using 'if' with 'progn' instead of simply using 'cond'? Quote
MSasu Posted February 1, 2013 Posted February 1, 2013 I would say is a matter of code ergonomics; it make the code much readable when need to test a single condition (simple or multiple, that it, combined whith AND and/or OR) and action accordingly. For sure, COND is a very powerful statement, one that many advanced programming languages lacks. Quote
BlackBox Posted February 1, 2013 Posted February 1, 2013 ... Certainly. IF is helpful when one must do 'this' (aka 'then') or 'that' (aka 'else') based upon the result of the IF statement's test expression. However, when you need to test for multiple scenarios, COND may be helpful... Just be prepared for the possibility of returning Nil (the last expression in the sublist), if none prior are non-Nil. Given the context of an IF statement, PROGN is only needed when one wants to group two or more expressions within the 'then' or 'else' expressions. HTH Quote
Reu Posted February 1, 2013 Author Posted February 1, 2013 ... Certainly. IF is helpful when one must do 'this' (aka 'then') or 'that' (aka 'else') based upon the result of the IF statement's test expression. However, when you need to test for multiple scenarios, COND may be helpful... Just be prepared for the possibility of returning Nil (the last expression in the sublist), if none prior are non-Nil. Given the context of an IF statement, PROGN is only needed when one wants to group two or more expressions within the 'then' or 'else' expressions. HTH So if my understanding of the 'progn' syntax is correct one could set up a code to test for multiple expressions in both the 'then' and 'else' expressions? Kind of like multiple 'and' statements? (if (this is true) (progn (do these things) ) (progn (else do these things) ) ) Quote
BlackBox Posted February 1, 2013 Posted February 1, 2013 So if my understanding of the 'progn' syntax is correct one could set up a code to test for [evaluate] multiple expressions in both the 'then' and 'else' expressions? FTFY Kind of like multiple 'and' statements? No... The AND function requires all expressions return non-Nil, whereas PROGN does not. Quote
Lee Roy Posted February 1, 2013 Posted February 1, 2013 Two ways to skin a cat for If/Then/Else Using "(if )" (if (<IF this is true>) (progn (<THEN do this>) (<and this>) (<and this>) ) (progn (<ELSE do this>) (<and this>) (<and this>) ) ) Using "(cond (t ))" (cond ((<IF this is true>) (<THEN do this>) (<and this>) (<and this>) ) (t (<ELSE do this>) (<and this>) (<and this>) ) ) I personally prefer to use "(if )" for single expression then/else statements and "(cond (t ))" for anything that requires multiple then/else statements. It's just easier for me to understand for some reason. Quote
MSasu Posted February 2, 2013 Posted February 2, 2013 Maybe by testing the below excerpts of code in VLISP Console will help you understand better: The test is evaluated as true: (if (= 1 1) "This is true!" "This isn't true!" ) The test is evaluated as false: (if (= 1 0) "This is true!" "This isn't true!" ) The test is evaluated as true, so expresions on first branch were evaluated one by one and the result of last evaluated one is returned: (if (= 1 1) (progn (setq a (+ 1 1)) (setq a (+ a 1)) ) (progn (setq a (- 1 1)) (setq a (- a 1)) ) ) The test is evaluated as false, so expresions on second branch were evaluated one by one and the result of last evaluated one is returned: (if (= 1 0) (progn (setq a (+ 1 1)) (setq a (+ a 1)) ) (progn (setq a (- 1 1)) (setq a (- a 1)) ) ) Quote
Lee Mac Posted February 2, 2013 Posted February 2, 2013 Here is another good explanation on the topic: http://www.theswamp.org/index.php?topic=13046.msg158557#msg158557 Quote
BIGAL Posted February 2, 2013 Posted February 2, 2013 What about repeat v's foreach ? Similar question Quote
Lee Mac Posted February 3, 2013 Posted February 3, 2013 What about repeat v's foreach ? Similar question Depends entirely on the application; sometimes repeat is more suitable, sometimes foreach. When iterating over items of a list, foreach is almost always the most suitable; whereas, when iterating using an index, or when repeating an operation a number of times, repeat would be used. As I say, it depends on the application, there is not a 'one size fits all' answer. Quote
irneb Posted February 3, 2013 Posted February 3, 2013 If/Cond AFAICT if is simply there for readability. As Lee Roy's shown in post #6, the if can be implemented instead through cond. It's simply a matter of semantics. Actually if is a derived function in most programming languages, either through the use of GoTo instructions (in more C-like languages) or through cond structures (in more Lisp-like languages). That's not to say all languages have the same structures though. E.g. you could compare VB's If Then ... ElseIf ... ElseIf ... Else structure to cond, but it's not fully equivalent since Lisp returns the last statement evaluated. This makes cond even more powerful, e.g.: (setq answer (getint "Enter any integer value: ")) (princ (strcat "\nThat is a " (cond ((> answer 0) "positive") ((< answer 0) "negative") (t "ZERO")) " integer.")) You'd need at least a temporary variable in VB / C* / Pascal / etc. to perform the same idea, since even VB's If Then ... ElseIf ... Else structure won't return the last value as lisp's cond does. There is one thing which is "missing" in AutoLisp, something equivalent to VB's select-case statement. It works a lot like cond, but due to how it works can be optimized a lot better. The reason behind this is because select operates on a specific value and then associates that value to a group of instructions. Therefore it can do the test once and immediately "know" which portion of the code to run - making for less testing if possible. It's not impossible to roll your own through lisp though. E.g. (defun Select (value operations else / opr) (eval (if (setq opr (assoc value operations)) (cadr opr) else))) (setq answer (getint "Enter a integer [0/1/2/3]: ")) (princ (strcat "\nThat integer is " (Select answer '((0 "Zero") (1 "One") (2 "Two") (3 "Three")) "not implemented in this code") ".")) Not as elegant as the VB select, but if Autolisp had macros / fexpr like other lisps have - it could have been made to look exactly the same or even better. No need for quotes. Repeat/ForEach/MapCar/While As Lee's pointed out it's a matter what the scenario calls for. I generally use foreach if I have to use each item in turn from a single list. MapCar works on more than one list at a time - so sometimes that's preferable to foreach, though its main purpose is to modify one or more lists into a new list containing calculated items. Repeat is simply a loop of a specified number of times, what you do inside is up to you. Similar with while, only now the condition is tested each time the loop iterates - instead of only once like in repeat (can be good if what you're doing inside is altering the condition, or bad if the condition could have been calculated beforehand - thus making it less efficient than it could have been). You can perform the same thing in mapcar as you can in foreach, and in some cases as in repeat / while. You'd generally use mapcar/foreach to iterate over one or more lists. But you'd use repeat / while to do something a number of times or until some condition fails. E.g. say you want to make a list which is 10 items long each item numbered 0 to 9: (setq lst nil n 10) (repeat n (setq lst (cons (setq n (1- n)) lst))) You could've done the same using while instead: (setq lst nil n 10) (while (>= (setq n (1- n)) 0) (setq lst (cons n lst))) But you'd be hard pressed to use foreach/mapcar in this case unless you already had a list which was 10 items long, e.g. ;; Using foreach (setq source '(A B C D F G H I J K) lst nil n 10) (foreach item source (setq lst (cons (setq n (1- n)) lst))) ;; Using mapcar (setq source '(A B C D F G H I J K) n -1) (setq lst (mapcar '(lambda (item) (setq n (1+ n))) source)) See how convoluted it gets when you try to force the use of something where it's not meant to be used? Even worse when you try to go the other way round. Say you want to square each integer in a list, this would be the simplest using mapcar ;; Using mapcar (setq source '(1 2 3 4 5)) (setq lst (mapcar '(lambda (i) (* i i)) source)) ;; Using foreach (setq source '(1 2 3 4 5) lst nil) (foreach i (reverse source) (setq lst (cons (* i i) lst))) ;; Using repeat (setq source '(1 2 3 4 5) lst nil n (length source)) (repeat n (setq lst (cons (* (nth (setq n (1- n)) source) (nth n source)) lst))) ;; Using while (setq source '(1 2 3 4 5) lst nil n (length source)) (while (>= (setq n (1- n)) 0) (setq lst (cons (* (nth n source) (nth n source)) lst))) Notice how foreach now requires a second list variable, and repeat / while requires a further index variable? Not to mention repeat/while could become very inefficient on long lists since the nth function would have to step through the list each time to get to the nth item. Quote
Lee Mac Posted February 3, 2013 Posted February 3, 2013 Great examples & explanations Irneb, well done. P.S. This: ;; Using mapcar (setq source '(1 2 3 4 5)) (setq lst (mapcar '(lambda (i) (* i i)) source)) Could be: ;; Using mapcar (setq source '(1 2 3 4 5)) (setq lst (mapcar '* source source)) Quote
irneb Posted February 3, 2013 Posted February 3, 2013 Great examples & explanations Irneb, well done. P.S. This: ;; Using mapcar (setq source '(1 2 3 4 5)) (setq lst (mapcar '(lambda (i) (* i i)) source)) Could be: ;; Using mapcar (setq source '(1 2 3 4 5)) (setq lst (mapcar '* source source)) Thanks for the compliment, and thanks for showing the idea behind mapcar even better - indicates that you can use 2 lists, even if they're the same list Quote
hmsilva Posted February 3, 2013 Posted February 3, 2013 @irneb @Lee Mac Great explanations, many thanks to both! :thumbsup: Henrique Quote
irneb Posted February 3, 2013 Posted February 3, 2013 @irneb@Lee Mac Great explanations, many thanks to both! :thumbsup: Henrique You're more than welcome! if Autolisp had macros / fexpr like other lisps have - it could have been made to look exactly the same or even better. No need for quotes.Actually it seems there's already a standard implementation in Common Lisp called case: http://www.lispworks.com/documentation/HyperSpec/Body/m_case_.htmhttp://en.wikipedia.org/wiki/Switch_statement#Common_Lisp Much less verbose than the VB Select-Case idea ... more reminiscent of Pascal's case statement: http://en.wikipedia.org/wiki/Switch_statement#Pascal Definitely less convoluted than C's fall-through switch-case idea: http://en.wikipedia.org/wiki/Switch_statement#C.2C_C.2B.2B.2C_D.2C_Java.2C_PHP.2C_ActionScript.2C_JavaScript Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.