all? or perhaps predicates that accept multiple args

For the Compleat Fan
Locked
Sammo
Posts: 180
Joined: Sat Dec 06, 2003 6:11 pm
Location: Loveland, Colorado USA

all? or perhaps predicates that accept multiple args

Post by Sammo »

Is there a simple and readable way of applying a predicate to multiple arguments? Perhaps something like:

Code: Select all

(all? integer? 1 2 3 "string")
I know I can write:

Code: Select all

(apply and (map integer? (list 1 2 3 "string")))
but, actually, I'd like to just write

Code: Select all

(integer? 1 2 3 "string")
which would return false (in this case because not all args are integers), or true (when all args are, in fact, integers).

It would be great if all predicates accepted multiple arguments.

Thanks,
-- Sam

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Re: all? or perhaps predicates that accept multiple args

Post by cormullion »

What about:

Code: Select all

 (exists integer? (list 1 2 3 "string"))
;-> 1
or

Code: Select all

(for-all integer? (list 1 2 3 "string"))
;-> nil

Kazimir Majorinc
Posts: 388
Joined: Thu May 08, 2008 1:24 am
Location: Croatia
Contact:

Re: all? or perhaps predicates that accept multiple args

Post by Kazimir Majorinc »

Additionally, if you insist on minimal syntax, you can play with fexprs (macros).

Code: Select all

(setf [print.supressed] true [println.supressed] true)      ; ----
(load "http://instprog.com/Instprog.default-library.lsp")   ; only println= used
(setf [print.supressed] nil [println.supressed] nil)        ; ----

(define-macro (flat-for-all)
  (letn((L (args))
        (r (cons 'and (map (lambda(x)(list (first L) x)) (rest L)))))
       (print "{" r "}=")
       (eval r)))
  
(println= (flat-for-all integer? 1 "hugo") "\n")

(dolist (i '(integer? float? string? list?))
  (letex((old-predicate i)
         (new-predicate (sym (push "s" (string i) -2)))) ;float?->floats?

        (define-macro (new-predicate)
                      (eval (append '(flat-for-all old-predicate) 
                                     (args))))
                                     
        (println= new-predicate )))

(println= "\n" (integers? 1 2 "hugo") "\n"
               (integers? 1 2 3 4)    "\n"
               (floats? 1.5 6.1)      "\n"
               (strings? "hi" "ho"))
Output:

Code: Select all

(flat-for-all integer? 1 "hugo")={(and (integer? 1) (integer? "hugo"))}=nil;

integers?=(lambda-macro () (eval (append '(flat-for-all integer?) (args))));
floats?=(lambda-macro () (eval (append '(flat-for-all float?) (args))));
strings?=(lambda-macro () (eval (append '(flat-for-all string?) (args))));
lists?=(lambda-macro () (eval (append '(flat-for-all list?) (args))));

(integers? 1 2 "hugo")={(and (integer? 1) (integer? 2) (integer? "hugo"))}=nil;
(integers? 1 2 3 4)={(and (integer? 1) (integer? 2) (integer? 3) (integer? 4))}=true;
(floats? 1.5 6.1)={(and (float? 1.5) (float? 6.1))}=true;
(strings? "hi" "ho")={(and (string? "hi") (string? "ho"))}=true;

Sammo
Posts: 180
Joined: Sat Dec 06, 2003 6:11 pm
Location: Loveland, Colorado USA

Re: all? or perhaps predicates that accept multiple args

Post by Sammo »

Thanks, cormullion, for the idioms using exists? and for-all. They are certainly cleaner than my "(apply and (map ...) version.

But, Kazimir, your solution is precisely what I was seeking. After creating the various macros, the syntax is as simple as can be, and, by expanding as an explicit and expression and then evaluating that expression, the function returns nil as soon as it encounters an argument for which the predicate is not true.

Thank you very much.
-- Sam

William James
Posts: 58
Joined: Sat Jun 10, 2006 5:34 am

Re: all? or perhaps predicates that accept multiple args

Post by William James »

This works for me:

Code: Select all

(define (for-all-args func)
  (for-all func (args)))

> (for-all-args number? 2 3 4 5)
true

> (for-all-args number? 2 3 'not 5)
nil

Locked