Macros 当看到0时停止计算的lisp宏乘法
我对LISP非常陌生,我不知道如何使我的无限参数函数在其中一个因子为0时停止计算其余参数。我试过这个Macros 当看到0时停止计算的lisp宏乘法,macros,lisp,Macros,Lisp,我对LISP非常陌生,我不知道如何使我的无限参数函数在其中一个因子为0时停止计算其余参数。我试过这个 (defmacro smart_multiplication (&rest l) (unless(member 0 l) `(* ,@l)) ) 但我认为这并不会停止乘法,直到它检查所有变量。一个,除非表单在谓词未命中时计算为nil: (macroexpand-1 '(smart-multiplication 1 2 0)) ; ==> nil 也许您应该使用ìf,
(defmacro smart_multiplication (&rest l)
(unless(member 0 l) `(* ,@l))
)
但我认为这并不会停止乘法,直到它检查所有变量。一个
,除非
表单在谓词未命中时计算为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*)
基本上,您不能将宏视为程序计算,因为它只抽象代码。从而使语法被改写成公共Lisp支持的东西。例如,除非是宏:
(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 code walker完全展开:
问题
现在代码看起来仍然不是很好。
改进留作练习:
- 块的返回可用于返回0,而无需执行open
*
函数调用
- 更好的是:不要使用嵌套的乘法调用
提示一个简单的解决方案:生成的代码可能类似于以下代码:
(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
参数不是无限长的。它们可以与变量调用参数limit
的值一样短,该值可以低至50。因此,在可移植代码中,不能假设函数允许超过50个数字作为参数。
(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))