Lisp trouble shooting

Lisp trouble shooting

Anonymous
Not applicable
897 Views
6 Replies
Message 1 of 7

Lisp trouble shooting

Anonymous
Not applicable

This lisp i have here seems to be getting hung up and i can not figure out why. On the first yes or no question i ask if you have more to check 

if you answer yes the command stops right there

if you answer no it goes the other way 

for some reason it seams to want to run the alert and stop for both yes and no 

I am just learning how to write lisp so it may not be the cleanest thing and might be a little unorthodox...

 

Any thoughts? 

Thanks for all the help 

0 Likes
898 Views
6 Replies
Replies (6)
Message 2 of 7

CodeDing
Advisor
Advisor
 (initget 1 "Y N Yes No")
(setq a (getkword "\nDo You Have More To Check? [Yes/No] <No>: "))
(cond ((= a "Y")))
(alert "Close Geometry Then Run DXF Again")
( when (= a "Y") (return nil)
(Princ)
(cond ((= a "N")))

...Looking at only this portion of your code, perhaps this can help get you on track:

;if you want a default option when user presses Enter, then remove 1 from initget
(initget "Y N Yes No")
;since we want the user to have a default option, we can implement a conditional statement for our setq
(setq a (cond ((getkword "\nDo You Have More To Check? [Yes/No] <No>: ")) ("N"))
;since we have allowed 4 responses (Y N Yes No), then let's redefine a to only 2 possible responses
(setq a (substr a 1 1))
;start our conditional statement for Y or N
(cond
      ((eq "Y" a);I prefer "eq" over "=" when using text
      ;Do stuff for Yes
      );end "Y"
      ((eq "N" a)
      ;Do stuff for No
      );end "N"
);end cond
;............ do more stuff

And once comments are removed, it looks much smaller and cleaner...

(initget "Y N Yes No")
(setq a (cond ((getkword "\nDo You Have More To Check? [Yes/No] <No>: ")) ("N"))
(setq a (substr a 1 1))
(cond
      ((eq "Y" a) 
      ;Do stuff for Yes
      );cond 1
      ((eq "N" a)
      ;Do stuff for No
      );cond 2
);cond
;simple comments should be left to help us trouble-shoot or for others to read our code

Best,

~DD

0 Likes
Message 3 of 7

Kent1Cooper
Consultant
Consultant

There are lots of mis-constructions in addition to what @CodeDing has already pointed out.  A couple of examples:  The first thing after a left parenthesis [except within a list] is supposed to be a function name, but there are no (when) or (return) functions.  You have (cond functions that get to a test condition and then close themselves without doing anything about it if the test is satisfied.  I think you need to read up about a lot of these functions in the AutoLisp Reference, studying the arguments they require, and what they return.

 

But I want to focus on the mis-use of (initget) -- don't do it this way:

 

    (initget "Y N Yes No")

 

The (initget) function allows you to get a whole word returned by typing only its capitalized initial(s) -- that's what the "init" in "initget" stands for -- and you can type them in either case, and you can type more of the word.  As you have it, all is well if the User types Y or N [or y or n] -- the "Y" or "N" will be returned, and the (cond) function [when properly constructed] will be able to detect the difference and act accordingly.

 

BUT your (cond) function checks for only those single letters, whereas the (getkword) prompt offers the full words Yes and No  as options.  If a User takes it up on that offer, and types one of those full words, or even just the first two letters of Yes, in any case combination, the full word "Yes" or "No" will be returned, and the (cond) function will not do anything, because it doesn't recognize either of those when all it's looking for is "Y" or "N".

 

Put the full words only  in the (initget) function, with the first letters capitalized:

 

    (initget "Yes No")

 

That way, the User can type Y or y, or YE or ye or Ye or yE, or YES or yes or Yes or yES or YEs or YeS or yEs or yeS, and from any of those the word "Yes" will be returned, in that case combination.  Or they can type N or n, or NO or no or No or nO, and the word "No" will be returned, again in that case combination [all valid inputs return the word in the exact case combination it has in the (initget) function argument, regardless of the case combination typed in by the User].

 

Then have the (cond) function check whether it's the full word "Yes" or "No"  instead of just the initial letters.

 

[Another option is to use only the initial letters  in (initget), without the full words:

 

    (initget "Y N")

 

and keep your (cond) checking for only those.  I don't like it, but it's not a particularly "bad" approach considering that most of the time, most Users are going to type only the one letter needed.  But if you do that, don't offer the options as whole words  in the (getkword) prompt, because if a User types more than the one letter, it will be an invalid keyword, and they'll be prompted again, until they type just a single initial letter.]

Kent Cooper, AIA
Message 4 of 7

CodeDing
Advisor
Advisor

Kent,

 

That was actually very informational for me. I've not know the best way to get consistent results from initget. Thank you.

0 Likes
Message 5 of 7

Anonymous
Not applicable

Wow, thanks for all that helpful information!

So after taking this info I have come up with this. For some reason it reruns nil and doesn't do anything. See the red notes.

 

(defun C:test()
(initget "Y N")
(setq a (cond (getkword "\nThis is a test. [Y/N] <N>: "))); it works fine by taking the cond statement out along with the line below 
(setq a (substr a 1 1)) ; I do not understand what this is doing...
(cond
((eq "Y" a)
(alert "Test for Y.") ; test action for "Y" 
); closes "Y"
((eq "N" a)
(alert "Test for N");test action for "N" 
); closes "N"
); closes the cond statement 
); this closes the "new command"

This is the other way taking those couple things out. Why does this happen?

 

 

(defun C:test()
(initget "Y N")
(setq a (getkword "\nThis is a test. [Y/N] <N>: "))
(cond
((eq "Y" a)
(alert "Test for yes.")
)
((eq "N" a)
(alert "Test for no")
)
)
)

 

Again thanks for all the info and help, I so much enjoy learning this!

 

0 Likes
Message 6 of 7

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

.... 

(defun C:test()
(initget "Y N")
(setq a (cond (getkword "\nThis is a test. [Y/N] <N>: "))); it works fine by taking the cond statement out along with the line below 
(setq a (substr a 1 1)) ; I do not understand what this is doing...
....

....


 

The (substr a 1 1) is for when the (initget) function included not just the initial letters but also the whole words.  If the User typed a whole word, that pares it down to just its initial letter, so the check for which one later on won't fail as it would if the variable held the whole word.  Read about the (substr) function in the AutoLisp Reference.  Since you have removed the whole words from the possibilities, you don't need that any more.

 

Your first (setq a... is not constructed correctly.  A (cond) function's conditions need to open with something to be evaluated, often a test function of some kind, and if whatever that is returns other than nil, and there are any following functions, they will be executed, or if no following functions, the return of the evaluation will simply be used in whatever the context of a containing function [in this case (setq) for the 'a' variable] is.  With a non-nil return, this condition will be satisfied, and any further conditions will be ignored.  But if the evaluation returns nil, it will move on to try the next possible condition.  Notice the ones further down testing for what's in 'a' have two  left parentheses at the start of each condition, one opening the condition, and when what is to be evaluated is a functionthe other opening the "test" function.  In this case the "test function" of the first condition is the (getkword) asking for User input.  It should be like this:

....
(setq a
(cond
(; open the first possible condition, for User input
(getkword "\nThis is a test. [Y/N] <N>: "); the "test condition" --
; If the User types a keyword initial, that will be a non-nil return, which will
;  be fed out as the return for (cond), and it will skip to the end of the overall
;  (cond) function, bypassing any further possible conditions.
; If the User hits Enter [to get the offered default], (getkword) returns nil,
; which will cause it to move on to try the next possible condition
); close the first [User-input] condition
    ("N")
; The "evaluation" is just the text string itself, not a test function, so there is
; not a second left parenthesis in this case. The evaluation is non-nil, so
;  that will "satisfy" the condition, and will be fed out as the result of the
; (cond) [and if there were any further conditions, all would be bypassed].
); close the overall (cond) function and put the result in the 'a' variable ....

Your second version doesn't account for the User hitting Enter to [try to] get the default No value.  If they do hit Enter, the 'a' variable will just be nil [which isn't like 0 or something -- it will not exist  at all], and the routine won't do either followup.

Kent Cooper, AIA
0 Likes
Message 7 of 7

Anonymous
Not applicable

That makes total sense! 

Thanks 

0 Likes