2014-10-07 42 views
0

我想通过自学来学习clisp。但完全混淆了如何处理变量。下面给出一个递归函数“mul”,用于乘以两个整数(+或 - )并用适当的符号得到结果。 “mul”使用另一个递归函数“sum”。clisp中funcall的arg变化值

(defun sum (n1 n2) 
    "Returns the sum of two integers" 
    (assert 
     (and (numberp n1) (integerp n1)) 
     (n1) 
     "N1 must be an integer,instead it's ~S" 
     n1) 
    (assert 
     (and (numberp n2) (integerp n2)) 
     (n2) 
     "N2 must be an integer,instead it's ~S" 
     n2) 
    (cond ((zerop n1) n2) 
     ((< n1 0) (sum (1+ n1) (1- n2))) 
     ((> n1 0) (sum (1- n1) (1+ n2))))) 

(defun mul (n1 n2) 
    "Returns the product of two integers" 
    (assert 
     (and (numberp n1) (integerp n1)) 
     (n1) 
     "N1 must be an integer,instead it's ~S" 
     n1) 
    (assert 
     (and (numberp n2) (integerp n2)) 
     (n2) 
     "N2 must be an integer,instead it's ~S" 
     n2) 
    (let* ((s (if (zerop n1) 0 
       (sum n2 (mul (if (< n1 0) (1+ n1) (1- n1)) n2))))(r s))    
     (if (or (and (> n1 0) (> n2 0)) (and (> n1 0) (< n2 0))) r 
     (if (or (and (< n1 0) (> n2 0)) (and (< n1 0) (< n2 0))) (- r) 0)))) 

当我运行

(MUL 4 4)或(MUL -3 4)

我得到正确与正确符号的结果。但

(MUL 3 -4)或(MUL -3 -4)

给出错误的-4和4分别结果。看起来else语句会在成功调用mul期间将n2的值更改为负值。有人可以解释我做错了什么,“-r”如何使n2消极。 在此先感谢。

下面是N1的不同值的跟踪和n2

MATCH> (mul 3 4) 
1. Trace: (MUL '3 '4) 
2. Trace: (SUM '4 '0) 
2. Trace: SUM ==> 4 
2. Trace: (SUM '4 '4) 
2. Trace: SUM ==> 8 
2. Trace: (SUM '4 '8) 
2. Trace: SUM ==> 12 
1. Trace: MUL ==> 12 
12 
MATCH> (mul 3 -4) 
1. Trace: (MUL '3 '-4) 
2. Trace: (SUM '-4 '0) 
2. Trace: SUM ==> -4 
2. Trace: (SUM '-4 '-4) 
2. Trace: SUM ==> -8 
2. Trace: (SUM '-4 '-8) 
2. Trace: SUM ==> -12 
1. Trace: MUL ==> -12 
-12 
MATCH> (mul -3 4) 
1. Trace: (MUL '-3 '4) 
2. Trace: (SUM '4 '0) 
2. Trace: SUM ==> 4 
2. Trace: (SUM '4 '-4) 
2. Trace: SUM ==> 0 
2. Trace: (SUM '4 '0) 
2. Trace: SUM ==> 4 
1. Trace: MUL ==> -4 
-4 
MATCH> (mul -3 -4) 
1. Trace: (MUL '-3 '-4) 
2. Trace: (SUM '-4 '0) 
2. Trace: SUM ==> -4 
2. Trace: (SUM '-4 '4) 
2. Trace: SUM ==> 0 
2. Trace: (SUM '-4 '0) 
2. Trace: SUM ==> -4 
1. Trace: MUL ==> 4 
4 

可以看出,只要N1是正MUL给出正确的结果。当n1为负值并且执行“else call”时会出现问题 - 然后调用n2变化的符号来求和。是因为(-r)吗?如果是的话为什么会发生?我的理解是,n2,s和r是三个单独的变量,r的值不应该改变n2。我对么 ? 如果不是,我会感激,如果有人向我解释他们的关系。我可能不会像usepa指出的那样使用这个复杂的代码,但这个解释对我理解lisp变量有很大的帮助。 在此先感谢。

+1

你试过跟踪你的代码吗?既然你使用全局定义的递归函数,你可以简单地评估'(trace sum)'和'(trace mul)',然后当你调用时,例如'(mul 3 -4)',你会看到所有的调用'mul'和'sum',你应该能够识别出现错误的地方。 – 2014-10-07 12:59:37

+0

是的。以下是(-3 4)和(3 -4)MATCH>(mul -3 4)的两条曲线:1. Trace:(MUL'-3'4) 2. Trace:(SUM'4'0) 2.跟踪:SUM ==> 4 2。Trace:(SUM'4'-4) 2. Trace:SUM ==> 0 2. Trace:(SUM'4'0) 2. Trace:SUM ==> 4 1. Trace:MUL == > -4 -4 MATCH>(mul 3 -4) 1.追踪:(MUL'3'-4) 2.追踪:(SUM'-4'0) 2.追踪:SUM ==> -4 2.跟踪:(SUM'-4'-4) 2.跟踪:SUM ==> -8 2.跟踪:(SUM'-4'-8) 2.跟踪:SUM ==> -12 1.跟踪:MUL ==> -12 -12 MATCH> – kkp 2014-10-08 04:50:54

+0

由于所有缩进都丢失,所以在注释中无法读取。使用问题下的**编辑**按钮并将信息添加到您的问题。 – 2014-10-08 11:13:35

回答

1

您的mul程序看起来过于复杂。我会重构程序如下:

(defun sum (n1 n2) 
    (cond 
    ((zerop n1) n2) 
    ((zerop n2) n1) 
    ((> n1 0) (sum (1- n1) (1+ n2))) 
    (t   (sum (1+ n1) (1- n2))))) 

(defun mul (n1 n2) 
    (cond 
    ((or (zerop n1) (zerop n2)) 0) 
    ((< n1 0) (mul (- n1) (- n2))) 
    (t  (sum n2 (mul (1- n1) n2))))) 
+1

考虑到你正在使用'zerop',请考虑使用'plusp'和'minusp',而不是显式比较零。 http://www.lispworks.com/documentation/HyperSpec/Body/f_minusp.htm – seh 2014-10-07 12:56:13

+0

简化的代码工作。是我的代码过于复杂。谢谢 – kkp 2014-10-08 04:42:00

+0

@kkp如果这个或任何答案已解决您的问题,请点击复选标记考虑[接受它](http://meta.stackexchange.com/q/5234/179419)。这向更广泛的社区表明,您已经找到了解决方案,并为答复者和您自己提供了一些声誉。没有义务这样做。 – uselpa 2014-10-12 20:37:13

1

以下不回答问题,但可能会帮助您解决问题。

首先我会改进一下格式。 ASSERT也可以用更短的CHECK-TYPE来代替。将debug值设置为max有助于跟踪。有了解释器,它可能不是必需的,但Clozure CL - 见下文 - 使用编译器。

(defun sum (n1 n2) 
    "Returns the sum of two integers" 
    (declare (optimize (debug 3))) 
    (check-type n1 integer) 
    (check-type n2 integer) 
    (cond ((zerop n1) n2) 
     ((< n1 0) (sum (1+ n1) (1- n2))) 
     ((> n1 0) (sum (1- n1) (1+ n2))))) 

(defun mul (n1 n2) 
    "Returns the product of two integers" 
    (declare (optimize (debug 3))) 
    (check-type n1 integer) 
    (check-type n2 integer) 
    (let ((s (if (zerop n1) 
       0 
      (sum n2 (mul (if (< n1 0) 
           (1+ n1) 
          (1- n1)) 
          n2)))))    
    (cond ((or (and (> n1 0) (> n2 0)) 
       (and (> n1 0) (< n2 0))) 
      s) 
      ((or (and (< n1 0) (> n2 0)) 
       (and (< n1 0) (< n2 0))) 
      (- s)) 
      (t 0)))) 

让我们尝试在Clozure CL

? (trace sum mul) 
NIL 
? (mul -2 1) 
0> Calling (MUL -2 1) 
1> Calling (MUL -1 1) 
    2> Calling (MUL 0 1) 
    <2 MUL returned 0 
    2> Calling (SUM 1 0) 
    3> Calling (SUM 0 1) 
    <3 SUM returned 1 
    <2 SUM returned 1 
<1 MUL returned -1 
1> Calling (SUM 1 -1) 
    2> Calling (SUM 0 0) 
    <2 SUM returned 0 
<1 SUM returned 0 
<0 MUL returned 0 
0 

你可以看到,(mul -1 1)做正确的事,但(mul -2 1)没有。