KeV
KeV

Reputation: 2891

Circular lists in Racket

It has been a while since i last programmed in Racket. Now i wanted to make a circular list in Racket as follows :

(define x (list 1 2))
(set-mcdr! (cdr x) x)

But this gives rises to the error :

set-mcdr!: contract violation
expected: mpair?
given: '(2)
argument position: 1st
other arguments...:
 '(1 2)

I'm surprised because (cddr x) is '() so I don't understand why he tells me "expected: mpair?" as '(2) is a pair (with cdr the empty list).

Thanks for your help!

Upvotes: 2

Views: 1455

Answers (4)

Shawn
Shawn

Reputation: 52529

You can also use Racket's built in functions for creating immutable cyclic data structures (This is what the Racket implementation of SRFI-1 circular-list uses internally). For example:

#lang racket/base

(define (make-circular-list . elems)
  (define ph (make-placeholder #f))
  (define circular-list (append elems ph))
  (placeholder-set! ph circular-list)
  (make-reader-graph circular-list))

(define x (make-circular-list 1 2)) ; x is written #0='(1 2 . #0#)

(require racket/list) ; for take
(println (take x 5)) ; '(1 2 1 2 1)

Upvotes: 0

John Clements
John Clements

Reputation: 17223

Other answers are of course entirely correct. I'd like to add, though, that there might be a different data structure that serves your needs better! I would take a look at in-cycle:

#lang racket

(define cyclic-sequence 
  (in-cycle (list 3 4 5)))

(for/list ([elt cyclic-sequence]
           [i (in-range 13)])
  elt)

Upvotes: 2

Sylwester
Sylwester

Reputation: 48765

Since you worked with Racket they introduced immutable pairs as standard. That means you cannot set car or cdr unless it's contructed of mcons.

However, in the SRFI-1 there is a constructor that makes circular lists and makes the list compatible with all procedures in #!racket that expects immutable lists:

#!racket

(require srfi/1)
(circular-list 1 2 3) ; ==> #0=(1 2 3 . #0#)

;; alternatively you can make a list circular
(apply circular-list '(1 2 3)) ; ==> #0=(1 2 3 . #0#)

(map cons '(1 2 3 4 5 6) (circular-list #t)) 
; ==> ((1 . #t) (2 . #t) (3 . #t) (4 . #t) (5 . #t) (6 . #t))

Upvotes: 1

Óscar López
Óscar López

Reputation: 236114

The list must be mutable if you want set-mcdr! to work, and all procedures used must also operate on mutable pairs; please check the documentation and notice that all the procedures contain an m as part of their name. For example, try this:

(require racket/mpair)

(define x (mlist 1 2))
(set-mcdr! (mcdr x) x)

Upvotes: 3

Related Questions