我很新的LISP,我不知道如何使我的无限参数功能停止评估其余的参数时,其中一个因素是0。已经试过lisp宏乘法,停止评估当看到一个0
(defmacro smart_multiplication (&rest l)
(unless(member 0 l) `(* ,@l))
)
但我认为这并不会停止倍增,直到它检查所有的变量。
我很新的LISP,我不知道如何使我的无限参数功能停止评估其余的参数时,其中一个因素是0。已经试过lisp宏乘法,停止评估当看到一个0
(defmacro smart_multiplication (&rest l)
(unless(member 0 l) `(* ,@l))
)
但我认为这并不会停止倍增,直到它检查所有的变量。
一个unless
形式计算为nil
时谓语不打这样:
(macroexpand-1 '(smart-multiplication 1 2 0))
; ==> nil
也许你应该使用ìf
因为你而希望它变成零?
(defmacro smart-multiplication (&rest l)
(if (member 0 l)
0
`(* ,@l)))
(macroexpand-1 '(smart-multiplication 1 2 3 0))
; ==> 0
(macroexpand-1 '(smart-multiplication 1 2 3))
; ==> (* 1 2 3)
请注意,它仅适用于字面零和,因为宏只知道变量符号和他们的价值观没有什么有它不会工作,当你有一个零变量:
(defparameter *zero* 0)
(macroexpand-1 '(smart-multiplication 1 2 3 *zero*))
; ==> (* 1 2 3 *zero*)
基本上你不能把宏看作是一个程序计算,因为它只是抽象代码。从而使得语法被重写成Common Lisp支持的东西。例如。 unless
是一个宏:
(macroexpand-1 '(unless some-predicate
result-1
result-2))
; ==> (if (not some-predicate) (progn result-1 result-2))
您需要在运行时检查为零值。
(defmacro smart-multiplication (&rest list)
(if (null list)
1
(let ((n0sym (gensym "mult")))
`(let ((,n0sym ,(first list)))
(if (zerop ,n0sym)
0
(* ,n0sym (smart-multiplication ,@(rest list))))))))
CL-USER 42 > (smart-multiplication (print 1) (print 2) (print 3))
1
2
3
6
CL-USER 43 > (smart-multiplication (print 1) (print 0) (print 3))
1
0
0
生成的代码,通过使用Lispworks 代码沃克完全展开:
CL-USER 46 > (pprint (walker:walk-form
'(smart-multiplication (print 1)
(print 0)
(print 3))))
(LET ((#:|mult973| (PRINT 1)))
(IF (ZEROP #:|mult973|)
0
(* #:|mult973|
(LET ((#:|mult974| (PRINT 0)))
(IF (ZEROP #:|mult974|)
0
(* #:|mult974|
(LET ((#:|mult975| (PRINT 3)))
(IF (ZEROP #:|mult975|) 0 (* #:|mult975| 1)))))))))
问题
现在,代码仍然不看起来非常好。 改进作为一个练习:
*
函数调用。提示一个简单的解决方案:将生成的代码可能是类似这样的:
(prog ((result 1)
value)
(setf value (print 1))
(when (zerop value)
(return 0))
(setf result (* result value))
(setf value (print 0))
(when (zerop value)
(return 0))
(setf result (* result value))
(setf value (print 3))
(when (zerop value)
(return 0))
(setf result (* result value))
(return result))
'&rest'参数不是无限的长度。它们可以与变量'call-arguments-limit'的值一样短,可以低至50.因此,在可移植代码中,您不能认为该函数允许超过50个数字作为参数。 –