2014-10-07 27 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)沒有。