明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 613|回复: 8

[提问] Autolisp是怎样区分表与函数调用的?

[复制链接]
发表于 2020-10-1 06:58:16 | 显示全部楼层 |阅读模式
本帖最后由 wrf610051 于 2020-10-1 17:08 编辑

(setq L 70 D 20)
(setq tj (list < L D))
(setq ans (cond (tj
                                        "Yes")
                                (T
                                        "No")
                        ))
;;想返回"No",但得到的是"Yes"。因为AutoLisp把tj认成了表,如何告诉它tj是函数调用呢?;;是不是cond后面的表达式,不会求值呢?



"觉得好,就打赏"
还没有人打赏,支持一下
发表于 2020-10-1 10:17:05 | 显示全部楼层
(setq L 70 D 20)
(setq tj (list < L D))
(setq ans (cond ((eval tj)
                                        "yes")
                                (T
                                        "No")
                        ))

评分

参与人数 1明经币 +1 收起 理由
wrf610051 + 1 很给力!

查看全部评分

发表于 2020-10-1 10:18:47 | 显示全部楼层
(setq tj (list < L D)) 改为 (c: tj (list < L D))
猜的
 楼主| 发表于 2020-10-1 17:12:10 | 显示全部楼层
start4444 发表于 2020-10-1 10:18
(setq tj (list < L D)) 改为 (c: tj (list < L D))
猜的

我写错了,想得到"No",因为(< 70 20)按条件表达式应为nil,但它把(< 70 20)看成一个表。
 楼主| 发表于 2020-10-1 17:21:50 | 显示全部楼层
start4444 发表于 2020-10-1 10:18
(setq tj (list < L D)) 改为 (c: tj (list < L D))
猜的

试了,还是得不到想要的结果。
(setq L 70 D 20)
(setq tj (list < L D))
返回:(#<SUBR @0000000029078a48 <> 70 20)
;;说明它已经把tj认为是一个函数了?下一句它为什么不按函数求值呢?
(setq ans (cond (tj "yes") (T "No")))
;返回:"yes"
发表于 2020-10-1 18:11:34 | 显示全部楼层
本帖最后由 wyl219 于 2020-10-1 18:28 编辑
wrf610051 发表于 2020-10-1 17:21
试了,还是得不到想要的结果。
(setq L 70 D 20)
(setq tj (list < L D))

(#<SUBR @0000000029078a48 <> 70 20) 这种是列表#<SUBR @000000002e938a48 <> 这种才是函数.
如果是提前赋值,就想你示例的函数那样,那直接把list去掉,tj保存判断后的布尔值就好.就像下面这样:
(setq L 70 D 20)
(setq tj (< L D))
(setq ans (cond (tj
                  "Yes")
            (T
              "No")
          ))


如果是想提前设定这个函数,再后面多次修改调用,可以把他写成函数.类似这样
(defun tj() (< L D))

(setq L 70 D 20)
(setq ans (cond ((tj);这里tj是个函数,要用括号括上
                  "Yes")
            (T
              "No")
          ))


如果tj的内容比较简单,可以考虑用lamba函数,就像这样.
(setq tj (lambda () (< L D)))
(setq L 70 D 20)
(setq ans (cond ((tj);这里和上面一样,要用括号括上
                  "Yes")
            (T
              "No")
          ))

还有一种方式,用read函数配合eval函数,注意tj保存的是字符串而不是列表.
(setq tj "(< L D)") ;这里没有list,否则后面会当成一个list函数
(setq L 70 D 20)
(setq ans (cond ((eval (read tj))
                  "Yes")
            (T
              "No")
          ))

注意,还有一种方式,即只使用eval不用read,像下面这样:

(setq L 70 D 20)
(setq tj (list < L D))

(setq ans (cond ((eval tj)
                  "Yes")
            (T
              "No")
          ))



单纯这样运行是没问题的,但是tj里保存的实际是 (< 70 20)这个列表,即用70和20代替L和D,然后在后面执行,如果之后修改L和D,对后面的执行没有影响的.因此tj里保存的是常量而非变量.
而用read函数,里面保存的是L和D的字符串,执行的时候才会调用L和D的值.

以上几种方式,lamba是更为正统的方式.

另外,可以猜一下下面的代码的输出值,如果弄清楚了,可能对你现在的疑惑有所帮助.
(defun tj() nil);一个返回值为nil的函数
(princ tj) ;打印tj变量保存的内容
(princ (tj)) ;打印tj函数的返回值



评分

参与人数 1明经币 +1 收起 理由
wrf610051 + 1 很给力!

查看全部评分

发表于 2020-10-1 22:06:44 | 显示全部楼层
本帖最后由 e2002 于 2020-10-3 10:29 编辑

LISP中:函数就是list。

上面回复中说了,需要使用 eval 对 list 求值。
但eval这个函数时运行时求值,所以 不要 用在 需要最后编译为 vlx/fas的 AutoLISP源代码 中, 否则极大可能出错。

之前也遇到的一个类似的问题,函数名称的参数传递,在源码中没有问题,但编译后再运行就是出错。
今天有点时间,总算找出了bug产生的原因,可能也是这种运行时求值的问题,编译时,由于不是运行,link无法获得内部函数的函数指针,只能获得 nil ,错误就此发生。
这个bug非常罕见,有时间我再深入琢磨之后,找时间写一个专门的文章。

;;=======     Update    ===========
在各位大神的指导下,对这个问题基本搞清楚了。
由于编译选项选上了“优化模式”与 “定位变量”,源码在编译时,内部函数也一起处理了,所以无法获得按原有的函数名称传递参数。
办法就是把内部函数移出去作为普通的函数。


 楼主| 发表于 2020-10-2 09:36:21 | 显示全部楼层
在此一并谢谢各位!
原地踏步解决了我的问题;
wyl219讲得很详细,让我明白了原由;
e2002讲到了涉及更深层次内容,我暂时无法理解。
发表于 2020-10-2 12:21:40 | 显示全部楼层
wrf610051 发表于 2020-10-2 09:36
在此一并谢谢各位!
原地踏步解决了我的问题;
wyl219讲得很详细,让我明白了原由;

当你给一个变量赋值的时候,会直接赋给其真实值,所以直接eval变量等同于直接赋值布尔值.
下面这个例子:
(setq L 70 D 20)
(setq tj (list < L D)) ;先赋值
(setq L 20 D 70);再修改变量
(if (= (eval tj) (< L D));tj里面的数据会跟着L D的值走么?
        (print "yes")
        (print "No")
)
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2025-5-17 17:21 , Processed in 0.193351 second(s), 26 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表