AutoLisp 2021 参数太少错误(应用(lambda

AutoLisp 2021 Too few arguments error on (apply (lambda

我们已经安装了最新的 Autodesk 2021 和我们的脚本之一(修改后的@Lee Mac),该脚本去除和格式化一些输入文本现在失败了。此脚本 运行 完美适用于 2019 年及以下。我似乎无法弄清楚为什么会有差异。

我已将原来的 "vl-catch-all-apply" 替换为 "apply",这样我就可以捕捉到错误。错误是:

Too few arguments

这发生在它命中 '(lambda 函数调用时。代码在下面的调用中:

(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
                           '(
                                ("2"     . "\\\\")
                                ("\n"        . "\\P")
                                (""       . "\\(\\[ACcFfHKkLlOopQTW])|\\[ACcFfHKkLlOopQTW][^\\;]*;|\\[ACcFfKkHLlOopQTW]")
                                ("/"  . "([^\\])\\S([^;]*)[/#\^]([^;]*);")
                                (""     . "\\(\\S)|[\\](})|}")
                                (""       . "[\\]({)|{")
                                ("\" . "(\\[ACcFfHKkLlOoPpQSTW])|({)|(})")
                                ("\\"     . "2")
                                (""     . "(?:.*\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
)
)

这个函数的调用如下。我检查了 "input",它与 2019 版本相同,并且使用 vlisp (vscode) 调试器正确填充了 str。我有 运行 相同的代码并通过两者输入,只有 2021 版本失败?

(setq input (GDD:removeinfo (vlax-get-or-create-object "VBScript.RegExp") input))

我对 LISP 不是很熟悉,所以我被卡住了。感谢您的帮助。

假设 <FUN> 代表:

'(lambda nil
  (vlax-put-property rgx 'global     actrue)
  (vlax-put-property rgx 'multiline  actrue)
  (vlax-put-property rgx 'ignorecase acfalse) 
  (foreach pair
   '(("2"     . "\\\\")
     ("\n"        . "\\P")
     (""       . "\\(\\[ACcFfHKkLlOopQTW])|\\[ACcFfHKkLlOopQTW][^\\;]*;|\\[ACcFfKkHLlOopQTW]")
     ("/"  . "([^\\])\\S([^;]*)[/#\^]([^;]*);")
     (""     . "\\(\\S)|[\\](})|}")
     (""       . "[\\]({)|{")
     ("\" . "(\\[ACcFfHKkLlOoPpQSTW])|({)|(})")
     ("\\"     . "2")
     (""     . "(?:.*\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)))))

您发布的代码,重写得更紧凑,如下所示:

(defun GDD:removeinfo (rgx str)
  (if (null (vl-catch-all-error-p
             (setq str (apply <FUN>))))
      str))

特别是,对 APPLY 的调用只有一个参数:

(apply <FUN>)

APPLY 在 Autolisp 中是一个有两个参数的函数:一个函数和一个参数列表。

目的是:

(apply f '(0 1))

... 就像您调用 (f 0 1) 一样进行评估,但有可能在运行时构建参数列表。

您在代码中只给 apply 一个参数,因此您还需要传递一个参数列表。 在您的情况下,那将是空列表:

(apply <FUN> nil)

不要将 vl-catch-all-apply 更改为 apply 以查看错误,只需将错误输出为 else 分支的一部分 if语句,例如:

(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
)

另外,虽然这段代码相对琐碎,但我不确定我是否同意你将 95% 的代码用于我的功能并删除我的标题和作者前缀。

编写该代码的人似乎不知道 progn 运算符。

也就是说,如果我们要评估多个表达式 e1e2、... 为了它们产生的副作用,我们不必这样做这个:

;; wrap expressions in a dummy lambda and apply empty arg list to it
(apply (lambda () e1 e2 ...) nil)

我们可以这样写:

(progn e1 e2 ...)

这仍然给我们留下了一种奇怪的代码味道,看起来像这样:

(setq str (progn .... (setq str value)))

代码为变量 str 分配了两次相同的值。深度嵌套的 (setq str value)value 放入 str 中,然后产生该值作为结果。它是 prognlambda 的原始表达式)的最后一个表达式,因此也返回该值。然后外层的 setq 又浪费地存储在 str 中。我们只需要一个:

;; 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))