[plt-scheme] define-union

From: Jacob Matthews (jacobm at cs.uchicago.edu)
Date: Fri Apr 18 22:43:14 EDT 2003

On Fri, 18 Apr 2003, Anton van Straaten wrote:

> How about modifying your spec slightly to allow this:
>
> 	(define-union snark? (foo? bar? number?))
>
> ...which would allow you to use this:
>
> 	(define-syntax define-union
> 	  (syntax-rules ()
> 	    ((_ name (pred ...))
> 	     (define (name x) (or (pred x) ...)))))
>
> ...which has the virtue of being very simple to implement and understand.
>

If you modify the spec just a little more, you don't need a macro at all.
You just need to be willing to use regular define rather than introducing
the new keyword define-union.

(define (union . predicates)
  (lambda (item) (ormap (lambda (f) (f item)) predicates)))

(define snark? (union foo? bar? number?))

> (snark? (make-foo 'a 'b))
#t
> (snark? (make-bar 'c 'b #f))
#t
> (snark? 453)
#t
> (snark? 'snark)
#f
> (snark? "I'm a snark! Honest!")
#f

If you want the error-detection Robby added in, you can use this ugly guy:

(define (union . predicates)
  (let* ([nonpredicate?
          (lambda (p)
            (if (and (procedure? p)
                     (procedure-arity-includes? p 1))
                #f
                p))]
         [bad-val (ormap nonpredicate? predicates)])
    (if (not bad-val)
        (lambda (item) (ormap (lambda (f) (f item)) predicates))
        (error 'union "not a predicate: ~e" bad-val))))

> (snark? (make-foo 'a 'b))
#t
> (snark? (make-bar 'c 'b #f))
#t
> (snark? 453)
#t
> (snark? 'snark)
#f
> (snark? "I'm a snark! Honest!")
#f
> (define mistake? (union number? cons))
union: not a predicate: #<primitive:cons>

Not pretty, but it works.

-jacob


Posted on the users mailing list.