2014-09-23 1 views
0

Я начинаю, и я пытаюсь научить себя Общему Лиспу, и во время моего самостоятельного изучения я написал функцию, которая, как я считаю, должна работать для рекурсивного добавления двух аргументов. Однако функция всегда терпит неудачу. Почему это?Рекурсивное дополнение в Lisp

(defun sum (n m) 
    ;;;Returns the sum of n and m using recursion 
    (cond ((eq m 0) n)) 
    (sum (1+ n) (1- m))) 

Как я понимаю, он должен постоянно добавлять от 1 до п, а декремент м до м не 0 в какой точке, рекурсивное добавление завершено

+0

Вы называете 'SUM' рекурсивно. Он останавливается, когда стек переполняется. Может быть, вы должны улучшить условие, чтобы остановить его само по себе ... Попробуйте использовать 'IF'. Также 'EQ' не для чисел. Используйте 'EQL' или' = '. –

+1

Отступ правилен в соответствии с кодом. 'cond' делает то, что выбрасывается (' n' или 'nil'), затем безусловная рекурсия, добавляя' n' и уменьшая 'm'. Он не вернет 'nil', так как он не остановится. Вы действительно получаете сообщение о переполнении стека? – Sylwester

+0

@Sylwester Да, я получаю сообщение переполнения стека в Emacs. Изучение того, что другие меня исправили, показали мне, как я на самом деле перепутался с моим заявлением cond и почему рекурсия никогда не заканчивается. – BurnedOut

ответ

5

Это действительно странно случай использования, чтобы сделать такое дополнение, но Я объясню вам, где ваши ошибки:

(defun sum (n m) 
    ;;;Returns the sum of n and m using recursion 
    (cond ((eq m 0) n)) ;; <= This line is ignored, you not returnin N. 
    (sum (1+ n) (1- m))) ;; <= this will be called forever 

Вы должны написать:

(defun sum (n m) 
    "Recursively increment N and decrement M untill M = 0" 
    (if (= m 0) ;; don't use EQ for numbers, use EQL or =. 
    n 
    (sum (1+ n) (1- m)))) ;; Otherwise recursive call 

Давайте проследим его, чтобы увидеть, как это работает:

CL-USER> (sum 0 10) 
    0: (SUM 0 10) 
    1: (SUM 1 9) 
     2: (SUM 2 8) 
     3: (SUM 3 7) 
      4: (SUM 4 6) 
      5: (SUM 5 5) 
       6: (SUM 6 4) 
       7: (SUM 7 3) 
        8: (SUM 8 2) 
        9: (SUM 9 1) 
         10: (SUM 10 0) 
         10: SUM returned 10 
        9: SUM returned 10 
        8: SUM returned 10 
       7: SUM returned 10 
       6: SUM returned 10 
      5: SUM returned 10 
      4: SUM returned 10 
     3: SUM returned 10 
     2: SUM returned 10 
    1: SUM returned 10 
    0: SUM returned 10 
10 

Если вы возьмете совет - не пытайтесь делать такие странные вещи, с помощью рекурсии, если вы хотите leard, как использовать его, попробуйте его некоторые естественно-рекурсивные случаи, такие как факториалы, фибоначчи, обработка дерева и тому подобное.

+0

или, по крайней мере, выровнять тестовые формы 'cond' друг с другом. Ошибка может быть легко обнаружена, если cond не был на том же уровне, что и рекурсивный вызов суммы. – soulcheck

+0

Конечно, он может использовать cond, но если у вас есть две ветви, если идиоматично. – coredump

+0

Да, ясно, если бы здесь было более идиоматично. Просто упомянуть cond в случае, если OP попадает в аналогичные проблемы в каком-то другом случае, где cond будет идиоматичным. – soulcheck

5

Я думаю, что у вас есть 2 простых опечаток:

  1. одна скобка слишком много и
  2. недостающие t в вашей статье cond.

То, что вы, вероятно, имел в виду:

(defun sum (n m) 
    (cond 
    ((eq m 0) n)    ; here you had one parenthesis too many 
    (t (sum (1+ n) (1- m))))) ; here you were missing the `t` symbol 
+1

Спасибо. Я думал, что мой код был просто совершенно неправильным, но немного поощрительно видеть, что у меня было 2 небольших опечатки от того, что у меня что-то работало. – BurnedOut

+0

@BurnedOut Нет, вы были довольно близки. Хотя я бы также использовал 'if', а не' cond' здесь, некоторые люди рекомендуют * всегда * использовать 'cond' по разным причинам, например [Руководство по стилю Racket] (http://www.ccs.neu.edu /home/matthias/Style/style/Choosing_the_Right_Construct.html#%28part._.Conditionals%29). – uselpa