AutoLisp 2021 Too few arguments error on (apply (lambda - lisp

We have installed the latest Autodesk 2021 and one of our scripts (a modified #Lee Mac) which strips and formats some input text now fails. This script runs perfectly on 2019 and below. I can't seem to work out why there is a difference.
I have substituted the original "vl-catch-all-apply" to "apply" so I could catch the error. The error is:
Too few arguments
This occurs as it hits the '(lambda function call. The code is below with the call:
(defun GDD:removeinfo (rgx str)
(if
(null
(vl-catch-all-error-p
(setq str
(apply
'(lambda nil
(vlax-put-property rgx 'global actrue)
(vlax-put-property rgx 'multiline actrue)
(vlax-put-property rgx 'ignorecase acfalse)
(foreach pair
'(
("\032" . "\\\\\\\\")
("\n" . "\\\\P")
("$1" . "\\\\(\\\\[ACcFfHKkLlOopQTW])|\\\\[ACcFfHKkLlOopQTW][^\\\\;]*;|\\\\[ACcFfKkHLlOopQTW]")
("$1$2/$3" . "([^\\\\])\\\\S([^;]*)[/#\\^]([^;]*);")
("$1$2" . "\\\\(\\\\S)|[\\\\](})|}")
("$1" . "[\\\\]({)|{")
("\\$1$2$3" . "(\\\\[ACcFfHKkLlOoPpQSTW])|({)|(})")
("\\\\" . "\032")
("" . "(?:.*\\n)*Const\\s+.*\\n")
("" . "\\w\\w\\d?\\s+\\d+\\s\\d+-\\d+-\\d+")
("" . "^\\s+\\n")
)
(vlax-put-property rgx 'pattern (cdr pair))
(setq str (vlax-invoke rgx 'replace str (car pair)))
)
)
)
)
)
)
str
)
)
The call to this function is below. I've checked the "input" and it is identical to the 2019 version that works and the str is populated properly using the vlisp (vscode) debugger. I've run the same code and input through both and only the 2021 version fails?
(setq input (GDD:removeinfo (vlax-get-or-create-object "VBScript.RegExp") input))
I'm not that familiar with LISP and I'm stuck. Thanks for your help.

Assuming <FUN> stands for:
'(lambda nil
(vlax-put-property rgx 'global actrue)
(vlax-put-property rgx 'multiline actrue)
(vlax-put-property rgx 'ignorecase acfalse)
(foreach pair
'(("\032" . "\\\\\\\\")
("\n" . "\\\\P")
("$1" . "\\\\(\\\\[ACcFfHKkLlOopQTW])|\\\\[ACcFfHKkLlOopQTW][^\\\\;]*;|\\\\[ACcFfKkHLlOopQTW]")
("$1$2/$3" . "([^\\\\])\\\\S([^;]*)[/#\\^]([^;]*);")
("$1$2" . "\\\\(\\\\S)|[\\\\](})|}")
("$1" . "[\\\\]({)|{")
("\\$1$2$3" . "(\\\\[ACcFfHKkLlOoPpQSTW])|({)|(})")
("\\\\" . "\032")
("" . "(?:.*\\n)*Const\\s+.*\\n")
("" . "\\w\\w\\d?\\s+\\d+\\s\\d+-\\d+-\\d+")
("" . "^\\s+\\n"))
(vlax-put-property rgx 'pattern (cdr pair))
(setq str (vlax-invoke rgx 'replace str (car pair)))))
The code you posted, rewritten more compactly, looks as follows:
(defun GDD:removeinfo (rgx str)
(if (null (vl-catch-all-error-p
(setq str (apply <FUN>))))
str))
In particular, the call to APPLY has only one argument:
(apply <FUN>)
APPLY in Autolisp is a function of 2 parameters: a function, and a list of arguments.
The intent is that:
(apply f '(0 1))
... is evaluated as-if you called (f 0 1), but with possibility of building the list of arguments at runtime.
You only gave one argument to apply in your code, so you need to also pass a list of arguments.
In your case, that would be the empty list:
(apply <FUN> nil)

Instead of changing vl-catch-all-apply to apply in order to see the error, simply output the error as part of the else branch of the if statement, for example:
(if
(null
(vl-catch-all-error-p
(setq str
(vl-catch-all-apply
...
)
)
)
)
str
(prompt (strcat "\nError: " (vl-catch-all-error-message str))) ;; Output error and return nil
)
Aside, whilst this code is relatively trivial, I'm not sure whether I agree with you appropriating 95% of the code for my function and stripping off my heading and author prefix.

Whoever wrote that code seemed not to be aware of the progn operator.
So that is to say, if we want to evaluate multiple expressions e1, e2, ... for the sake of a side effect that they produce, we do not have to do this:
;; wrap expressions in a dummy lambda and apply empty arg list to it
(apply (lambda () e1 e2 ...) nil)
We can just write this:
(progn e1 e2 ...)
That still leaves us with a strange code smell which looks like this:
(setq str (progn .... (setq str value)))
The code is assigning the variable str twice with the same value. The deeply nested (setq str value) puts value into str and then yields that value as a result. It's the last expression of the progn (originall, of the lambda) and so that value is also returned. Then the outer setq wastefully stores it in str again. We just need one or the other:
;; set str as the side effect of the last form in the
;; progn; also yield that value.
(progn e1 e2 ...(setq str value))
;; assign value yielded from progn to str, then also
;; yield that value.
(setq str (progn e1 e2 ... value))

Related

Lisp basic print function getting user input

I am supposed to write a program that gets simple user input as a string and the code supposed to writes back a response (name, are you a person etc.) The program suppose to terminate when word 'bye' is typed. The code is below:
(defun x()
(setq words "empty")
(loop while (string/= words "BYE")
(setq words (read-delimited-list #\~)
(write-line words)
(format t "ROBBIE%: Hello, who are you?")
(case (string-include "I'm" words)
(format t "ROBBIE%: Nice to see you, how are you?")
((string-include "Hi" words)
(format t "ROBBIE%: How are you?")
(or (string-include "fine" words) (string-include "person" words))
(format t "ROBBIE%: No I'm a computer")))
(format t "BYE"))
(x)
However, when I compile this on program 2 errors pop up:
Line2:3 warning: undefined variable: COMMON-LISP-USER:: WORDS
Line3:3 error: during macroexpansion of (LOOP WHILE (STRING/= WORDS "BYE") ...). Use BREAK-ON-SIGNALS to intercept.
I've done programming in python but this is extremely complicated lang for me and I need some help understanding why this isn't working? Any advice is greatly appreciated!
When you do this:
(defun x ()
(setf words "foo"))
then words is not defined. It references some global variable, and if that doesn't exist, it will create it, but possibly with some strange behaviour regarding scope and extent. This is not portable code.
In order to introduce a local variable, use let:
(defun x ()
(let ((words "foo"))
;; words is is scope here
)
;; but not here
)
Loop (in the more usual »extended« form) uses loop keywords for all its clauses. There is no implicit body. In order to do something, you might use do, which allows multiple forms to follow:
(defun x ()
(let ((words "foo"))
(loop while (string/= words "bye")
do (setf words (read-line …))
(format …))))
Case uses compile-time values to compare using eql:
(case something
(:foo (do-a-foo))
((:bar :baz) (do-a-bell))
(t (moooh)))
This doesn't work with strings, because strings are not eql unless they are the same object (i. e. they are eq). In your case, you want a cond:
(cond ((string-include-p words "Whatever")
…)
((string-include-p words "yo man")
…))
For interaction with the user, you'd maybe want to use the bidirectional *query-io* stream:
(format *query-io* "Who am I?")
and
(read-line *query-io*)
Read-line gives you strings, and seems much better suited to your task than read-delimited-list, which has other use cases.
Let me focus on aspects of your code not already covered by other solutions.
Loop
Here is your loop structure:
(let ((words "empty"))
(loop
while (string/= words "BYE")
do
(progn
(setq words (read-line)))))
First of all, after do you don't need (progn ...). You could write equally:
(let ((words "empty"))
(loop
while (string/= words "BYE")
do (setq words (read-line))))
Having to initialize words to some arbitrary value (called sometime a sentinel value) is a code smell (not always a bad thing, but there might be better alternatives). Here you can simplify the loop by using a for clause.
(loop
for words = (read-line)
while (string/= words "BYE")
do ...)
Also, you may want to use until with a string= test, this might be more readable:
(loop
for words = (read-line)
until (string= words "BYE")
do ...)
Search
You can test for string inclusion with SEARCH. Here is a little commented snippet of code to showcase how string manipulation function could work:
(defun test-I-am (input)
(let ((start (search "I'am" input)))
(when start
;; we found an occurrence at position start
;; let's find the next space character
(let ((space (position #\space input :start start)))
(when space
;; we found a space character, the name starts just after
(format nil "Hello ~a!" (subseq input (1+ space))))))))
With this simple algorithm, here is a test (e.g. in your REPL):
> (test-i-am "I'am tired")
"Hello tired!"
Replace read-delimited-list with read-line, case with cond and balance some parentheses. Here is working solution, including some function for string-inclusion:
(defun string-include (string1 string2)
(let* ((string1 (string string1)) (length1 (length string1)))
(if (zerop length1)
nil
(labels ((sub (s)
(cond
((> length1 (length s)) nil)
((string= string1 s :end2 (length string1)) string1)
(t (sub (subseq s 1))))))
(sub (string string2))))))
(defun x ()
(let ((words "empty"))
(format t "ROBBIE%: Hello, who are you?~%")
(loop while (string/= words "BYE") do
(progn
(finish-output)
(setq words (read-line))
(cond ((string-include "I'm" words)
(format t "ROBBIE%: Nice to see you, how are you?~%"))
((string-include "Hi" words)
(format t "ROBBIE%: How are you?~%"))
((or (string-include "fine" words)
(string-include "person" words))
(format t "ROBBIE%: No I'm a computer~%")))))
(format t "BYE")))
Then you just call it:
(x)

For-each loop over pairs in Racket

I'm trying to print a list of pairs of values (representing key/value pairs) in Racket.
Here's the code I have right now:
#lang racket
(define (write-json keyvalues)
(displayln "{")
(for-each
(lambda (kv) (
(displayln (format "~a: ~a," (car kv) (cdr kv)))))
keyvalues)
(displayln "}"))
(write-json (list (cons "a" 1) (cons "b" 2)))
When I run the example, it prints:
{
a: 1,
Then, it crashes with this error message:
application: not a procedure;
expected a procedure that can be applied to arguments
given: #<void>
arguments...: [none]
context...:
/.../racket/collects/racket/private/map.rkt:58:19: loop
"test.rkt": [running body]
for-loop
run-module-instance!125
perform-require!78
Any idea what's going on?
Thanks!
This is a paren issue. You have an extra set of parentheses around your lambda's body, ie:
( (displayln (format "~a: ~a;" (car kv) (cdr kv))) )
Since displayln is used for side effect, its output is void, hence why your error message states that you're trying to run (#<void>).
In general, whenever you get an error stating "expected a procedure that can be applied to arguments", see if you have parentheses issues in your code block. Editors like Dr. Racket would highlight that region for you.

why an extra value at end of hash?

I wrote a function to convert alist to hash:
(defun hash-alist (alist)
"Convert association list to a hash table and return it."
(let ((my-hash (make-hash-table :test 'equal)))
(dolist (entry alist)
(if (gethash (car entry) my-hash)
(error "repeated key"))
(puthash (car entry) (cdr entry) my-hash))
my-hash))
but when I run it as following, why I get nil at the end?
Run:
(setq a '(("a" . 2) ("b" . 1)))
(setq b (hash-alist a))
(maphash (lambda (x y) (princ (format "%s:%d " x y) t))
b)
Output:
a:2 b:1 nil
nil is the return value of maphash. Nothing more than that.
It is the way that you are evaluating the maphash sexp that causes the return value to be printed.
If you look in buffer *Messages* you might see something like this (depending on how you evaluate the expression):
Evaluating...
a:2 b:1
Buffer `*Pp Eval Output*' is in mode `Emacs-Lisp'. For info on the mode: `C-h m'.
nil
The return value is documented in the Elisp manual, node Hash Access. It should also be, but is not, documented in the doc string.
Every Lisp expression has a value.
c-x c-e evaluates an expression and prints the result.
If you evaluate (+ 1 2) you see that it evaluates to 3. If you evaluate a maphash expression, then it evaluates to NIL. So this is printed.
Since your code calls functions which produce output, you see that output printed before the return value. So there is no extra NIL. It is just the NIL that is the result.

In Elisp how to dynamically assign value to a variable which also selected dynamically (in let form.)

I have a alist of known variables and corresponding functions with nil parameter list, inside body it use that known non-parameter (or global) variable.
for e.g.
(defun funA ()
(message "%s" varA))
(defun funB ()
(message "%s" varB))
...
(setq alist
'((varA . funA)
(varB . funB)
...
))
Similar element in alist can be added / deleted dynamically.
I want to run all these function in another function where the value of known variable assigned dynamically in LET form.
(defun call-each-fun-of-alist ()
(dolist (e alist)
(let (( (car e) (read-from-minibuffer "value: ") ))
(funcall (cdr e)))))
(Yes it will throw error, but I wanted to similar thing, possible without EVAL)
For known element of alist (like first I could do
(let ((varA (read-from-minibuffer "value: ")))
(funcall (cdr (assoc 'varA alist))))
But alist is dynamically updated and I what to run all functions in alist
and the value for corresponding variable will come dynamically.
Please let me know how I can define
call-each-fun-of-alist
(not necessarily but without calling EVAL inside call-each-fun-of-alist, if not possible without EVAL than I like to know it also.)
You could do this with letf (cl-letf in recent Emacs). It binds values like let but allows 'places' or 'generalized variables' as well as simple variable names.
(defun call-each-fun-of-alist ()
(cl-dolist (e alist)
(cl-destructuring-bind (variable . function) e
(cl-letf (((symbol-value variable)
(read-from-minibuffer
(format "value for %s: "
variable))))
(funcall function)))))
Note that this will fail with an error unless the variables named in alist have previously been declared as dynamic variables using defvar. Look up 'generalized variables' in the Elisp manual for more information.
Another solution would be to use cl-progv, which takes parallel lists of variable names and values to bind dynamically:
(defun call-each-fun-of-alist ()
(cl-dolist (e alist)
(cl-destructuring-bind (variable . function) e
(cl-progv
(list variable)
(list (read-from-minibuffer
(format "value for %s: "
variable)))
(funcall function)))))
In Common Lisp this is provided by PROGV - dynamic binding of a variable given the symbol of the variable.
GNU Emacs should have PROGV in its Common Lisp emulation.
This is all you need -- no need for progv or destructing bind stuff:
(defun call-each-fun-of-alist (alist)
(dolist (e alist)
(set (car e) (read-from-minibuffer "value: "))
(funcall (cdr e))))
(defvar my-alist '((varA . funA) (varB . funB)))
(call-each-fun-of-alist my-alist)
Or if you really want to see a let binding for some reason:
(defun call-each-fun-of-alist (alist)
(dolist (e alist)
(eval `(let ((,(car e) (read-from-minibuffer "value: ")))
(funcall (cdr e))))))

A simple lisp program

I want to write this program to find a keyword in a list. If found then print the list. But errors occur, i can't solve it. Please give me some suggestions. I am a newbie for lisp.
The main program is two dolist(two for in C) and find keyword in a list of list(two dimension array).
(defun kanna_find (key)
(let (
(result 0)
(kanna-table (list
(list "あ" "ア" "a")
(list "い" "イ" "i")
)
) ;; End of kanna table
) ;; End of let var define
(dolist (result kanna-table)
(dolist (item result)
(if (string= item key)
(print result))
) ;; End of the second dolist
) ;; End of the first dolist
) ;; End of let
)
(kanna_find "あ")
Below is the debug info
Debugger entered--Lisp error: (void-variable  )
(list "い"   "イ"   "i")
(list (list "あ" "ア" "a") (list "い"   "イ"   "i"))
(let ((result 0) (kanna-table ...)) (dolist (result kanna-table) (dolist ... ...)))
kanna_find("あ")
eval((kanna_find "あ"))
eval-last-sexp-1(nil)
eval-last-sexp(nil)
call-interactively(eval-last-sexp nil nil)
recursive-edit()
(list "あ" "ア" "a")
(list "い" "イ" "i")
Do you notice how the spaces in the second line are longer than the ones on the first line? That's because they're not ASCII spaces, so emacs doesn't recognize them as spaces. Rather emacs thinks they're variable names, so it complains to you that there's no variable called " " (thus the space in the void-variable error).
You seem to be looking for this one-liner:
;; return a sublist tail of list-of-strings whose first element is string
;; or nil if string is not found
(member string list-of-strings)
Your code is terribly formatted. Try this style, which is used by about 99.5 million of the world's 100 million or so Lisp programmers:
(defun kanji_find (key)
(let ((result 0)
(kanji-table (list (list "あ" "ア" "a")
(list "い" "イ" "i"))))
(dolist (result kanji-table)
(dolist (item result)
(if (string= item key)
(print result))))))
Nobody writes comments about individual closing parentheses; that is ridiculous! You're turning Lisp into Ada.
Your text editor (being Emacs, after all) can show you the balancing pairs of parentheses and manage the indentation for you.
In the end, the indentation is your main visual clue about what goes with what.
The (result 0) binding in your code is useless and has nothing to do with the result variable in the outer dolist.