Умножение чисел в списке (по координатам) без использования 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))