From: Jimka
Subject: case of predicates
Date: 
Message-ID: <1162731439.390886.61330@m7g2000cwm.googlegroups.com>
Quite often a COND is simply a series of predicates all
applied to the same value, and the COND is essentially
finding the first predicate that is true of the original value.

Is there already a more primative way to do this in common lisp?
It is possible to write (as shown below) and not very pretty,
but perhaps there is some better way using built-in functions
with ?test and ?key keyword parameters?

I want to make a case statement where every clause of
the case simply tests a predicate applied to the same argument.
So it is sort of a case but with a ?test keyword (sort of!).

(defmacro case-predicate (obj &rest clauses)
  (let ((var (gensym "var")))
    (let ((expand-predicate (lambda (clause)
                              (if (eq t (car clause))
                                  clause
				`(( ,(car clause) ,var)
				  ,@(cdr clause))))))
      `(let ((,var ,obj))
	 (cond ,@(mapcar expand-predicate clauses))))))


(case-predicate expression
    (null nil)
    (numberp (format t "~A" expression))
    (stringp expression)
    (list-of-strings? (some-function-1 expression))
    (list-of-numbers? (some-function-2 expression))
    (t (error "did not match")))

From: John Thingstad
Subject: Re: case of predicates
Date: 
Message-ID: <op.tijo1qrnpqzri1@pandora.upc.no>
On Sun, 05 Nov 2006 13:57:19 +0100, Jimka <·····@rdrop.com> wrote:

> Quite often a COND is simply a series of predicates all
> applied to the same value, and the COND is essentially
> finding the first predicate that is true of the original value.
>
> Is there already a more primative way to do this in common lisp?
> It is possible to write (as shown below) and not very pretty,
> but perhaps there is some better way using built-in functions
> with ?test and ?key keyword parameters?
>
> I want to make a case statement where every clause of
> the case simply tests a predicate applied to the same argument.
> So it is sort of a case but with a ?test keyword (sort of!).
>
> (defmacro case-predicate (obj &rest clauses)
>   (let ((var (gensym "var")))
>     (let ((expand-predicate (lambda (clause)
>                               (if (eq t (car clause))
>                                   clause
> 				`(( ,(car clause) ,var)
> 				  ,@(cdr clause))))))
>       `(let ((,var ,obj))
> 	 (cond ,@(mapcar expand-predicate clauses))))))
>
>
> (case-predicate expression
>     (null nil)
>     (numberp (format t "~A" expression))
>     (stringp expression)
>     (list-of-strings? (some-function-1 expression))
>     (list-of-numbers? (some-function-2 expression))
>     (t (error "did not match")))
>

typecase

(defun what-is-it (x)
    (format t "~&~S is ~A.~%"
            x (typecase x
                (float "a float")
                (null "a symbol, boolean false, or the empty list")
                (list "a list")
                (t (format nil "a(n) ~(~A~)" (type-of x))))))

It's in the ANSI standard.

Often method overloading is what you want. It allows you to separate the  
instances
and is easier to extend.

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
From: Pascal Costanza
Subject: Re: case of predicates
Date: 
Message-ID: <4r679rFq2qn9U1@individual.net>
Jimka wrote:
> Quite often a COND is simply a series of predicates all
> applied to the same value, and the COND is essentially
> finding the first predicate that is true of the original value.
> 
> Is there already a more primative way to do this in common lisp?
> It is possible to write (as shown below) and not very pretty,
> but perhaps there is some better way using built-in functions
> with ?test and ?key keyword parameters?
> 
> I want to make a case statement where every clause of
> the case simply tests a predicate applied to the same argument.
> So it is sort of a case but with a ?test keyword (sort of!).
> 
> (defmacro case-predicate (obj &rest clauses)
>   (let ((var (gensym "var")))
>     (let ((expand-predicate (lambda (clause)
>                               (if (eq t (car clause))
>                                   clause
> 				`(( ,(car clause) ,var)
> 				  ,@(cdr clause))))))
>       `(let ((,var ,obj))
> 	 (cond ,@(mapcar expand-predicate clauses))))))
> 
> 
> (case-predicate expression
>     (null nil)
>     (numberp (format t "~A" expression))
>     (stringp expression)
>     (list-of-strings? (some-function-1 expression))
>     (list-of-numbers? (some-function-2 expression))
>     (t (error "did not match")))

(typecase expression
   (null nil)
   ((satisfies numberp) ...)
   ((satisfies stringp) ...)
   ...
   (t ...))


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Jimka
Subject: Re: case of predicates
Date: 
Message-ID: <1162735198.709712.249730@m7g2000cwm.googlegroups.com>
cool SATISFIES is the trick.

Pascal Costanza wrote:
>
> (typecase expression
>    (null nil)
>    ((satisfies numberp) ...)
>    ((satisfies stringp) ...)
>    ...
>    (t ...))
> 
> 
> Pascal
>
From: Steven Haflich
Subject: Re: case of predicates
Date: 
Message-ID: <kvw3h.1920$vP1.1476@newssvr13.news.prodigy.com>
Pascal Costanza wrote:
 > (typecase expression
 >   (null nil)
 >   ((satisfies numberp) ...)
 >   ((satisfies stringp) ...)
 >   ...
 >   (t ...))

Huh, Pascal?  Your use of the satisfies type is entirely
equivalent to use of the appropriate type predicates

(typecase expression
   (null nil)
   (number ...)
   (string ...)
   ...
   (t ...))

but any particular implementation is more likely to optimize a literal
type inside typecase than it is a satisfies type with an arbitrary 
function.  They _are_ equivalent, but my version is stylistically more 
common and therefore more likely to be optimized.
From: Richard Krushelnitskiy
Subject: Re: case of predicates
Date: 
Message-ID: <1162790769.514801.200830@b28g2000cwb.googlegroups.com>
Steven Haflich wrote:
> Huh, Pascal?  Your use of the satisfies type is entirely
> equivalent to use of the appropriate type predicates
>
> (typecase expression
>    (null nil)
>    (number ...)
>    (string ...)
>    ...
>    (t ...))
>
> but any particular implementation is more likely to optimize a literal
> type inside typecase than it is a satisfies type with an arbitrary
> function.  They _are_ equivalent, but my version is stylistically more
> common and therefore more likely to be optimized.

This is only a guess, but judging from the original post, Pascal might
have been trying to make a point that TYPECASE can test the cases using
a predicate, even if no such type exists. Of course one can use define
a type beforehand, but would the implementation treat the following any
differently than an explicit (SATISFIES PLUS-OR-MINUS-P) inside
TYPECASE?

(defun plus-or-minus-p (char)
  (or (char= char #\+) (char= char #\-)))

(deftype plus-or-minus ()
  '(satisfies plus-or-minus-p))
From: Pascal Costanza
Subject: Re: case of predicates
Date: 
Message-ID: <4r88n2Fq1scsU1@individual.net>
Steven Haflich wrote:
> Pascal Costanza wrote:
>  > (typecase expression
>  >   (null nil)
>  >   ((satisfies numberp) ...)
>  >   ((satisfies stringp) ...)
>  >   ...
>  >   (t ...))
> 
> Huh, Pascal?  Your use of the satisfies type is entirely
> equivalent to use of the appropriate type predicates
> 
> (typecase expression
>   (null nil)
>   (number ...)
>   (string ...)
>   ...
>   (t ...))

This occurred to me as well after I have posted it, but this is only 
because I have shortened the example too much. The OP's example had 
predicates for which there are no (obvious) corresponding types.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/