Как мне зациклить более длинный список с картой, которая зависит от более короткого списка, обертывающего его, чтобы применить некоторую функцию к более длинному списку в Common Lisp?

В принципе, я хотел бы получить эквивалент этого кода на Common Lisp, но предпочтительно в более удобном виде.

(defun circular (items) 
  (setf (cdr (last items)) items))
(map 'list #'(lambda (x y) (+ x y)) 
     (circular '(1 2 3)) '(2 3 4 5))
;; ==> (3 5 7 6)
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
72
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я думаю, что ваш код почти достаточно хорош. (Единственная проблема в том, что вы не должны изменять список в кавычках).

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

(defun map-circular (result-type function governing-sequence &rest reused-lists)
  "Apply `function` to successive sets of arguments in which one argument is obtained from each sequence.
The result has the length of `governing-sequence`."
  (let ((last-cells (mapcar (lambda (list)
                              (let ((cell (last list)))
                                (setf (cdr cell) list)
                                cell))
                            reused-lists)))
    (unwind-protect
         (apply #'map result-type function governing-sequence reused-lists)
      (dolist (cell last-cells)
        (setf (cdr cell) nil)))))

Тест:

(defparameter l1 (list 1 2))
(defparameter l2 (list 1 2 3))
(map-circular 'list #'+ '(1 2 3 4) l1 l2)
==> (3 6 7 7)
l1
==> (1 2)
l2
==> (1 2 3)

Если вы используете пакет SERIES, вы можете использовать функцию SERIES, которая:

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

Это работает, если элементы известны статически, т.е. не из списка значений, заданных во время выполнения.

Здесь ниже код сканирует список и в то же время перебирает бесконечный ряд 1 2 3 .... Оба ряда повторяются параллельно с mapping, как s и n, и отображение генерирует ряд (cons s n). Результат собирается в виде списка:

(collect 'list
  (mapping ((s (scan 'list '(a b c d e f g h)))
            (n (series 1 2 3)))
    (cons s n)))

Результат:

((A . 1) (B . 2) (C . 3) (D . 1) (E . 2) (F . 3) (G . 1) (H . 2))

Серии подлежат слиянию потоков, и расширенный код:

(let* ((#:out-823 (list 1 2 3)))
  (let (#:elements-816
        (#:listptr-817 '(a b c d e f g h))
        #:items-821
        (#:lst-822 (copy-list #:out-823))
        #:items-826
        (#:lastcons-813 (list nil))
        #:lst-814)
    (declare (type list #:listptr-817)
             (type list #:lst-822)
             (type cons #:lastcons-813)
             (type list #:lst-814))
    (setq #:lst-822 (nconC#:lst-822 #:lst-822))
    (setq #:lst-814 #:lastcons-813)
    (tagbody
     #:ll-827
      (if (endp #:listptr-817)
          (go series::end))
      (setq #:elements-816 (car #:listptr-817))
      (setq #:listptr-817 (cdr #:listptr-817))
      (setq #:items-821 (car #:lst-822))
      (setq #:lst-822 (cdr #:lst-822))
      (setq #:items-826 ((lambda (s n) (cons s n)) #:elements-816 #:items-821))
      (setq #:lastcons-813 (setf (cdr #:lastcons-813) (cons #:items-826 nil)))
      (go #:ll-827)
     series::end)
    (cdr #:lst-814)))

Если вам нужно передать в функцию произвольный список, вы можете сделать свой циклический список, вызвав (nconc list list), который проще написать. Поскольку вы, вероятно, не хотите изменять входной список, вместо этого вы можете написать это:

(defun circularize (list)
  (let ((list (copy-list list)))
    (nconc list list)))

Другие вопросы по теме