2017-03-09 62 views
-1

我很新的LISP,我不知道如何使我的无限参数功能停止评估其余的参数时,其中一个因素是0。已经试过lisp宏乘法,停止评估当看到一个0

(defmacro smart_multiplication (&rest l) 
    (unless(member 0 l) `(* ,@l)) 
) 

但我认为这并不会停止倍增,直到它检查所有的变量。

+0

'&rest'参数不是无限的长度。它们可以与变量'call-arguments-limit'的值一样短,可以低至50.因此,在可移植代码中,您不能认为该函数允许超过50个数字作为参数。 –

回答

0

一个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)) 
0

您需要在运行时检查为零值。

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

问题

现在,代码仍然不看起来非常好。 改进作为一个练习:

  • 从块的回报可以用来返回0,不执行开*函数调用。
  • 甚至更​​好:不要使用嵌套调用乘法...

提示一个简单的解决方案:将生成的代码可能是类似这样的:

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