<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1">
<title></title>
</head>
<body>
<tt>Or you can use (define-union snark (foo bar number) like this:<br>
<br>
(define-macro define-union<br>
(lambda (name types)<br>
(if (not (list? tu<br>
(define (add-? s)<br>
</tt><tt> (if (not (symbol? s))<br>
(error 'define-union "~a is not a data type" s))<br>
(string->symbol (string-append (symbol->string s) "?")))</tt><br>
<tt> (let ([discriminators (map add-? types)]<br>
[final-descriminator (add-? name)])<br>
(define (with-handlers-discriminators)<br>
(define (iter discs)<br>
(if (empty? discs)<br>
empty<br>
(cons `(with-handlers ([exn? (lambda args (error
'define-union "~a is not a data type discriminator"<br>
,(car
discs)))])<br>
,(car discs))<br>
(iter (cdr discs)))))<br>
(cons `list (iter discriminators)))<br>
`(define ,final-descriminator<br>
(let ([discs ,(with-handlers-discriminators)])<br>
(define (check-discriminator f)<br>
(if (not (and (procedure? f)<br>
(procedure-arity-includes? f 1))) ; checks
that can be called with one argument<br>
(error 'define-union "~a is not a data type
discriminator" f)))<br>
(for-each check-discriminator discs)<br>
(lambda (data)<br>
(ormap (lambda (disc) (disc data)) discs)))))))<br>
<br>
<br>
Hope there aren't any missing parens.</tt><br>
<br>
<br>
Jacob Matthews wrote:<br>
<blockquote type="cite"
cite="midPine.LNX.4.50.0304182111410.21748-100000@randal.cs.uchicago.edu">
<pre wrap=""> For list-related administrative tasks:
<a class="moz-txt-link-freetext" href="http://list.cs.brown.edu/mailman/listinfo/plt-scheme">http://list.cs.brown.edu/mailman/listinfo/plt-scheme</a>
On Fri, 18 Apr 2003, Anton van Straaten wrote:
</pre>
<blockquote type="cite">
<pre wrap="">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.
</pre>
</blockquote>
<pre wrap=""><!---->
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?))
</pre>
<blockquote type="cite">
<pre wrap="">(snark? (make-foo 'a 'b))
</pre>
</blockquote>
<pre wrap=""><!---->#t
</pre>
<blockquote type="cite">
<pre wrap="">(snark? (make-bar 'c 'b #f))
</pre>
</blockquote>
<pre wrap=""><!---->#t
</pre>
<blockquote type="cite">
<pre wrap="">(snark? 453)
</pre>
</blockquote>
<pre wrap=""><!---->#t
</pre>
<blockquote type="cite">
<pre wrap="">(snark? 'snark)
</pre>
</blockquote>
<pre wrap=""><!---->#f
</pre>
<blockquote type="cite">
<pre wrap="">(snark? "I'm a snark! Honest!")
</pre>
</blockquote>
<pre wrap=""><!---->#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))))
</pre>
<blockquote type="cite">
<pre wrap="">(snark? (make-foo 'a 'b))
</pre>
</blockquote>
<pre wrap=""><!---->#t
</pre>
<blockquote type="cite">
<pre wrap="">(snark? (make-bar 'c 'b #f))
</pre>
</blockquote>
<pre wrap=""><!---->#t
</pre>
<blockquote type="cite">
<pre wrap="">(snark? 453)
</pre>
</blockquote>
<pre wrap=""><!---->#t
</pre>
<blockquote type="cite">
<pre wrap="">(snark? 'snark)
</pre>
</blockquote>
<pre wrap=""><!---->#f
</pre>
<blockquote type="cite">
<pre wrap="">(snark? "I'm a snark! Honest!")
</pre>
</blockquote>
<pre wrap=""><!---->#f
</pre>
<blockquote type="cite">
<pre wrap="">(define mistake? (union number? cons))
</pre>
</blockquote>
<pre wrap=""><!---->union: not a predicate: #<primitive:cons>
Not pretty, but it works.
-jacob
</pre>
</blockquote>
</body>
</html>