Потоки схемы и циклические списки

В Scheme/Lisp я пытаюсь создать функцию, которая преобразует список в круговой список. Поэтому я считаю, что мне нужно построить бесконечный поток, в котором конец списка указывает на начало списка.

Вот мой код:

(define (rotate-list l1 l1copy)
  (if (null? (force (cdr l1)))
      (cons (car l1) (delay l1copy)))
      (cons (car l1) (delay (rotate-list (force (cdr l1)) l1copy))))

Вся помощь приветствуется.


person CodeKingPlusPlus    schedule 04.02.2013    source источник


Ответы (1)


Нет, вам не нужны потоки для создания кругового списка.

Существует два подхода к созданию круговых списков: стандартный подход Scheme и подход Racket (поскольку conses Racket неизменяемы). Я рассмотрю примеры с использованием функции circular-list SRFI 1. Вот эталонная реализация:

(define (circular-list val1 . vals)
  (let ((ans (cons val1 vals)))
    (set-cdr! (last-pair ans) ans)
    ans))

Что это делает, так это находит последнюю пару в списке заданных значений и set-cdr! возвращает ее к началу этого списка. Довольно просто, правда?

В Racket conses неизменяемы, поэтому set-cdr! не существует. Вместо этого Racket делает это следующим образом:

(define (circular-list val1 . vals)
  (let ([ph (make-placeholder #f)])
    (placeholder-set! ph
      (cons val1 (let loop ([vals vals])
                   (if (null? vals)
                     ph
                     (cons (car vals) (loop (cdr vals)))))))
    (make-reader-graph ph)))

При этом используется make-reader-graph для обработки циклов. Очень круто. :-)

person Chris Jester-Young    schedule 04.02.2013
comment
Не могли бы вы привести пример создания буквального циклического списка в Racket, пожалуйста? В документации упоминается что-то вроде #0=(1 . #0#), но REPL не принимает это выражение. - person Alexey; 24.03.2019