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)
signature.asc
Description: OpenPGP digital signature
_________________________________________________ For list-related administrative tasks: http://lists.racket-lang.org/listinfo/users

