[racket] doubly linked list lib

From: Vincent St-Amour (stamourv at ccs.neu.edu)
Date: Wed Aug 31 11:50:08 EDT 2011

Are you planning to put this on PLaneT?

Vincent


At Wed, 31 Aug 2011 11:46:34 +0200,
Marijn wrote:
> 
> [1  <multipart/signed (7bit)>]
> [1.1  <multipart/mixed (7bit)>]
> [1.1.1  <text/plain; ISO-8859-1 (quoted-printable)>]
> 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
> [1.1.2 dlist.rkt <text/plain (base64)>]
> (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) , at 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 
> [1.1.3 list-editor.rkt <text/plain; UTF-8 (quoted-printable)>]
> #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)
> [1.2 OpenPGP digital signature <application/pgp-signature (7bit)>]
> 
> [2  <text/plain; us-ascii (7bit)>]
> _________________________________________________
>   For list-related administrative tasks:
>   http://lists.racket-lang.org/listinfo/users



Posted on the users mailing list.