(module maybe mzscheme
(require (lib "contract.ss")
(lib "plt-match.ss")
(lib "etc.ss")
(lib "list.ss"))
(provide (all-defined))
(define-struct maybe () (make-inspector))
(define-struct (nothing maybe) () (make-inspector))
(define-struct (just maybe) (value) (make-inspector))
(define (maybe-return a)
(make-just a))
(define (maybe-bind m f)
(if (nothing? m)
(make-nothing)
(f (just-value m))))
(define (combine* c ms)
(foldl
(lambda (x y)
(combine c x y))
(make-nothing)
ms))
(define (combine c x y)
(match (list x y)
[(list (struct nothing ()) (struct nothing ()))
(make-nothing)]
[(list (struct nothing ()) (struct just (_y)))
y]
[(list (struct just (_x)) (struct nothing ()))
x]
[(list (struct just (_x)) (struct just (_y)))
(make-just (c _x _y))]))
(define (maybe-equal? equal? x y)
(match (list x y)
[(list (struct nothing ()) (struct nothing ()))
#t]
[(list (struct nothing ()) (struct just (_y)))
#f]
[(list (struct just (_x)) (struct nothing ()))
#f]
[(list (struct just (_x)) (struct just (_y)))
(equal? _x _y)]))
(define (maybe/c fc)
(flat-named-contract
"Maybe(alpha)"
(lambda (x)
(or (nothing? x)
(and (just? x)
((flat-contract-predicate fc) (just-value x)))))))
(define f->f/maybe
(opt-lambda (f [fail #f])
(lambda args
(let ([r (apply f args)])
(if (eq? fail r)
(make-nothing)
(make-just r))))))
(define assq/maybe (f->f/maybe assq))
(define assv/maybe (f->f/maybe assv))
(define (map/maybe f lst)
(reverse
(foldl (lambda (e a)
(let ([me (f e)])
(if (nothing? me)
a
(cons (just-value me) a))))
empty
lst))))