Умножение чисел в списке (по координатам) без использования mapcar в Лиспе

У меня проблемы с выводом моего кода, я думаю, что это когда я проверяю условия для нулевого из моих списков.

Вопрос, который я пытаюсь завершить: написать функцию vecmul это будет принимать в качестве входных данных два простых списка чисел. vecmul должен умножать эти списки по координатам, как если бы они умножали векторы. Предположим, что два списка имеют одинаковую длину. [Например, (vecmul '(2 3 4 5) '(1 4 5 2)) возвращается (2*1 3*4 4*5 5*2) или же (2 12 20 10), Вам не разрешено использовать mapcar для этой функции]

Пока у меня есть

(defun vecmul (list list2)
  (cond ((null list) 0)
     (t (cons (* (car list) (car list2))
                 (vecmul (cdr list) (cdr list2))))))

[170]> (setq l '(2 4 6))
(2 4 6)
[171]> (setq r '(1 3 5))
(1 3 5)
[172]> (vecmul l r)
(2 12 30 . 0)

Я получаю правильные цифры, просто в списке добавляется "." и "0" в конце списка. Я уверен, что это потому, что я не останавливаю рекурсию правильно или не работаю правильно. Я просто не совсем уверен, как это исправить.

2 ответа

Решение

Вы поняли это почти правильно. Тем не менее, вы заканчиваете свой список с 0когда правильное завершение nil, Этот код работает:

(defun vecmul (list list2)
  (cond ((null list) nil)
     (t (cons (* (car list) (car list2)) (vecmul (cdr list) (cdr list2))))))

Когда вы звоните (cons 1 2)записана клетка против (1 . 2), обозначение (1 2 3 4 5) это просто сокращение для (1 . (2 . (3 . (4 . (5 . nil))))), Если cdr из последних минусов 6не nilтогда вы получите (1 . (2 . (3 . (4 . (5 . 6))))), который сокращается до (1 2 3 4 5 . 6),

Нил Форрестер ответил на ваш вопрос.

Еще несколько замечаний. Используйте современные имена в Лиспе: first а также rest,

(defun vecmul (list1 list2)
  (cond ((null list1) nil)
        (t (cons (* (first list1) (first list2))
                 (vecmul (rest list1) (rest list2))))))

Если у вас есть простое верное и ложное решение, IF может быть лучше. Поскольку операции со списком задействованы, я бы написал это следующим образом и не использовал WHEN,

(defun vecmul (list1 list2)
  (if (null list1)
      nil
    (cons (* (first list1) (first list2))
          (vecmul (rest list1) (rest list2)))))

Лучше всего использовать конструкцию цикла или отображение в реальном коде. Рекурсия, как указано выше, имеет ограничение глубины стека. Цикл не имеет этого ограничения.

(defun vecmul (list1 list2)
  (loop for e1 in list1 and e2 in list2
        collect (* e1 e2)))

или же

(defun vecmul (list1 list2)
  (mapcar #'* list1 list2))
Другие вопросы по тегам