Hi Laurent,

On 08/30/11 09:18, Laurent wrote:
> Thank you very much for this nice intermediate solution, though I need
> constant-time append, split, insert, remove, + pointers to items, etc.
> Mutation does seem unavoidable, right.

I implemented a doubly-linked list, not so long ago, connected to a GUI
that can insert and delete items and saw no way to make the list
functional with multiple simultaneous editors in the GUI. The
implementation is as a straightforward cyclical doubly-linked list. I
toyed with the idea of having a separate handle object to represent the
list versus just the nodes, and there are some rudiments of that left in
the code, but in the end the user code uses a special 'top element to
indicate where the cyclical list is supposed to start.

Good luck,

Marijn
(module dlist racket
  (provide dlist dl-insert dl-insert-right dl-remove for/dlist)
  
  (require (for-syntax racket))
  
  (define (dl-print dl p write?)
    (let ((print (if write? write display)))
      (display #\( p)
      (let loop ((l dl))
        (print (_dl-val l) p)
        (let ((right (_dl-right l)))
          (if (eq? right dl)
              (display #\) p)
              (begin (display " " p) (loop right)) )))))

  (define (dl-sequence l)
    (if (dl-empty? l)
        (make-do-sequence (lambda () (values #f #f #f (lambda (lk) #f) #f #f)))
        (let ((last (_dl-left l)))
          (make-do-sequence
           (lambda () ; val    next  start        last?
             (values _dl-val _dl-right l #f #f (lambda (lk v) (not (eq? lk 
last)))) )))))
  
  ;;; link
  (define-struct _dl (left val right) #:mutable
    #:property prop:custom-write dl-print
    #:property prop:sequence dl-sequence
    ) ; end link

  (define (dlh-print dlh p write?)    
    (dl-print (_dlh-link dlh) p write?))

  (define (dlh-sequence l)
    (let ((h (_dlh-link l)))
      (make-do-sequence
       (lambda () ; val    next       start        last?
         (values _dl-val _dl-right (_dl-right h) (lambda (lk) (not (eq? lk h))) 
#f #f) ))))
  
  ;;; list handle
  (struct _dlh (link) #:mutable
    #:property prop:custom-write dlh-print
    #:property prop:sequence dlh-sequence
    ) ; end handle
  
  (define (dl-empty)
    (_dl #f #f #f))
  
  (define (dlh-empty)
    (_dlh (dl-empty)))
  
  (define (dl-empty? l)
    (not (_dl-left l)))

  (define (dl-one-element? l)
    (eq? l (_dl-left l)))
  
  (define (dlh-empty? l)
    (dl-empty? (_dlh-link l)))
    
;  (define (dlist a b c)
 ;   (shared ((la (_dl #f a lb))
  ;           (lb (_dl la b lc))
   ;          (lc (_dl lb c #f)) )
    ;  la))
  
  (define-syntax (dlist stx)
    (syntax-case stx ()
      ((_) #'(dl-empty))
      ((_ a b ...)
       (let* ((temps (generate-temporaries #'(a b ...))) (links `(,(last temps) 
,@temps ,(first temps))))
         #`(shared
               #,(let loop ((ret '()) (links links) (vals (syntax->list #'(a b 
...))))
                   (if (empty? vals) (reverse ret)
                       (loop (cons #`(#,(cadr links) (make-_dl #,(car links) 
#,(car vals) #,(caddr links))) ret)
                             (cdr links) (cdr vals) )))
             #,(cadr links))))))

  (define-syntax-rule (dlisth a b ...) (_dlh (dlist #f a b ...)))    
  
  (define-syntax-rule (_dl-insert val link link-next new-link set-link-next! 
set-link-prev!)
    (if (dl-empty? link) (dlist val)
        (let* ((next (link-next link)) (new (new-link link val next)))
          (set-link-next! link new)
          (and next (set-link-prev! next new))
          new)))
  
  (define (dl-insert-right v l)
    (_dl-insert v l _dl-right _dl set-_dl-right! set-_dl-left!))
  
  (define (dl-insert v l)
    (let-syntax ((dl (syntax-rules () ((_ r v l) (_dl l v r)))))
      (_dl-insert v l _dl-left dl set-_dl-left! set-_dl-right!)))

  (define-syntax-rule (_dlh-insert v l insert)
    (let ((h (_dlh-link l)))
      (if h
          (insert v h)
          (set-_dlh-link! l (dlist v)) )))
    
  (define (dlh-insert-front v l)
    (_dlh-insert v l dl-insert-right))
  
  (define (dlh-insert-back v l)
    (_dlh-insert v l dl-insert))
  
  (define (dl-remove link (ret #f))
    (if (or (dl-empty? link) (dl-one-element? link))
        (dl-empty)
        (let ((l (_dl-left link)) (r (_dl-right link)))
          (set-_dl-right! l r)
          (set-_dl-left! r l)
          (if ret l r))))
  
  (define (dl-reverse link)
    (if (dl-empty? link) (dl-empty)
        (let ((left (_dl-left link)) (right (_dl-right link)))
          (set-_dl-right! link left)
          (set-_dl-left! link right)
          (let loop ((lft link) (lnk right))
            (if (eq? lnk link) left
                (let ((rght (_dl-right lnk)))
                  (set-_dl-right! lnk lft)
                  (set-_dl-left! lnk rght)
                  (loop lnk rght)))))))
  
;  (define (dlh-reverse l)
          
  (define-syntax-rule (for/dlist clauses body ... val)
    (_dl-right (for/fold ((ret (dl-empty))) clauses (dl-insert-right val ret))))
  
  ) ; end module 
#lang racket/gui

;(require dlist)
(require "./dlist.rkt")

(define list-editor%
  (class vertical-panel%
    (init init-values parent)
    (super-new (parent parent))
    
    (define widget-list (dlist 'top))
    
    (define (redisplay)
      (send this change-children (lambda (l) (cdr (for/list ((w widget-list)) 
w)))))
    
    (define (insert-item val link)
      (let* ((v (new vertical-panel% (parent this)))
             (lk (dl-insert v link))
             (ins (new button% (parent v) (label "insert")
                       (callback (λ (b e)
                                   (insert-item "1" lk) (redisplay) )) ) )
             (h (new horizontal-pane% (parent v)))
             (t (new text-field% (parent h) (label "") (init-value val)))
             (del (new button% (parent h) (label "del")
                       (callback (λ (b e) (dl-remove lk) (send this 
delete-child v))) )))
        lk))
    
;    (send this begin-container-sequence)
    (for ((v init-values)) (insert-item v widget-list))
;    (send this end-container-sequence)
    
    (let* ((v (new vertical-panel% (parent this)))
           (lk (dl-insert v widget-list)))
      (new button% (parent v) (label "append")
           (callback (λ (b e) (insert-item "1" lk) (redisplay))) ))
   
    )) ; end define class

(define root (new frame% (label "List Editor") (stretchable-height #f)))
  
(new list-editor% (parent root) (init-values '("1" "2" "3")))

(send root show #t)

Attachment: signature.asc
Description: OpenPGP digital signature

_________________________________________________
  For list-related administrative tasks:
  http://lists.racket-lang.org/listinfo/users

Reply via email to