(define-record-type edge ((from) (to)) ((mark 'unvisited))) (define-record-discloser type/edge (lambda (p) `(edge ,(edge-from p) ,(edge-to p) ,(edge-mark p)))) (define (edges->sorted-graph edges) (let ((sorted-graph '())) (for-each (lambda (e) (let ((edge (edge-maker (car e) (cdr e)))) (cond ((assoc (car e) sorted-graph) => (lambda (p) (set-cdr! p (cons edge (cdr p))))) (else (set! sorted-graph (cons (cons (car e) (list edge)) sorted-graph)))))) edges) sorted-graph)) (define (get-edges-from from graph) (cdr (assoc from graph))) (define (shortest-path from to graph) (define (loop from) (if (equal? from to) (values 0 (list to)) (let ((depth-path (fold-left (lambda (min-depth-path e) (if (equal? (edge-mark e) 'unvisited) (begin (set-edge-mark! e 'visited) (call-with-values (lambda () (loop (edge-to e))) (lambda (depth path) (let ((min-depth (car min-depth-path))) (set-edge-mark! e 'unvisited) (if (or (not min-depth) (and depth (< depth min-depth))) (cons depth path) min-depth-path))))) min-depth-path)) (cons #f #f) (get-edges-from from graph)))) (if (car depth-path) (values (+ (car depth-path) 1) (cons from (cdr depth-path))) (values #f #f))))) (call-with-values (lambda () (loop from)) (lambda (depth path) path)))