#loops #while-loop #lisp
#циклы #while-цикл #lisp
Вопрос:
Я пытаюсь создать функцию пар в Lisp. Функция pairs получает два входных сигнала, затем создает пару друг с другом и составляет один список. Вот мой код:
(defun npair (s1 s2)
(let ((result '()))
(cond ((null s1) s2)
((null s2) s1)
(t (loop
(when (null s1) (return result))
(while (not (null s2))
(setq result (cons (list (car s1) (car s2)) result))
(setq s2 (cdr s2)))
(setq s1 (cdr s1)))))))
Эта функция должна была возвращать как (npair '(a b c) '(1 2))
-> ((a 1) (a 2) (b 1) (b 2) (c 1) (c 2))
Но мой результат только ((a 1) (a 2))
. Пожалуйста, помогите!
Комментарии:
1. ПОКА неизвестно, ваш код не может выполняться.
2. Ваши
null
условия case означают, что это неправильное декартово произведение. Если какой-либо список пуст, результат должен быть пустым: потому что комбинация каждого элемента непустого списка с каждым элементом пустого списка является пустой. Конечно, мы можем определить функцию так, как нам нравится; просто вряд ли она будет иметь полезную ценность, если она выдает безвозмездно специальные специальные случаи.
Ответ №1:
Если вы хотите накапливать значения из внутреннего цикла во внешнем цикле, вам, вероятно, лучше просто накапливать значения, а не пытаться сделать это путем изменения переменных:
(loop for e1 in p1
append (loop for e2 in p2
collect (list e1 e2)))
Ваше форматирование также неверно, обычай заключается в том, чтобы не помещать завершающие круглые скобки в новую строку.
Таким образом, используя конструкцию цикла сверху, вся ваша функция будет:
(defun npair (p1 p2)
(loop for e1 in p1
append (loop for e2 in p2
collect (list e1 e2))))
Приятный, простой и вполне читаемый.
Ответ №2:
В то время как другие показали вам лучшие альтернативы для достижения желаемого результата, чем ваша реализация, вот причина, по которой ваша реализация не работает: вы изменяете значение s2
to null
при объединении первого элемента s1
с элементами of s2
и никогда не восстанавливаете исходное значение s2
перед обработкой оставшихся элементов of s1
. (Это одна из нескольких веских причин, по которым вы должны перебирать входные значения, не изменяя их в первую очередь.)
Вот версия вашей реализации, которая на самом деле работает, потому что она не изменяет свои входные данные:
(defun npair (s1 s2)
(let ((result '()))
(cond ((null s1) s2)
((null s2) s1)
(t (loop for e1 in s1
do (loop for e2 in s2
do (push (list e1 e2) result)))
(nreverse result)))))
Ответ №3:
судя по всему, результат, на который вы надеетесь, называется декартовым произведением.
Реализация, которую я использую на языке программирования Scheme, выглядит следующим образом:
(define (product . args)
(if (null? args)
(list '())
(apply append
(map (lambda (rest)
(map (lambda (first)
(cons first rest))
(car args)))
(apply product (cdr args))))))
Например, вот вывод с использованием схемы Chez:
> (product '(a b c) '(1 2))
((a 1) (b 1) (c 1) (a 2) (b 2) (c 2))