5

I look for compacting expression like:

(let ( (val (complex-expr ...)) )
  (or (pred1 val) (pred2 val) ...(predN val)))

Instead I like something:

(apply-some (complex-expr ...) '(pred1 pred2 ... predN))
Drew
  • 77,472
  • 10
  • 114
  • 243
gavenkoa
  • 3,452
  • 20
  • 37
  • It is very similar to -some->, except that you need to invert the predicates. But I don't know of any function that'd do it in standard library, so writing one yourself doesn't sound like a bad idea. Perhaps you could suggest this as a feature to Dash library maintainers. – wvxvw Sep 19 '15 at 16:46

4 Answers4

7

You can use cl-some to apply a list of predicates to a value:

(cl-some (lambda (p) (funcall p "some value"))
         '(vectorp listp stringp))

I suppose you could wrap this in a function. Although I don't love this name, say:

(defun cl-emos (preds v)
  "Are any PREDS true for V.

This is the \"opposite\" of `cl-some', which sees if one pred is
true for any values."
  (cl-some (lambda (p) (funcall p v))
           preds))

Example uses:

(cl-emos '(vectorp listp stringp)
         "string")
;; => t
(cl-emos '(vectorp listp stringp)
         42)
;; => nil

Note: Whatever you name it, of course you shouldn't prefix it with cl-. I did that just to make the comparison clear with cl-some.


Compared to cl-some, I prefer the way that ormap works in Scheme and Racket: It returns the truthy value, not just t (even when the predicate only returns t). To do that, here, just replace (funcall p v) with (and (funcall p v) v):

(defun cl-emos (preds v)
  "Are any PREDS true for V.

This is the \"opposite\" of `cl-some', which sees if one pred is
true for any values."
  (cl-some (lambda (p) (and (funcall p v) v)) ;; <======
           preds))

(cl-emos '(vectorp listp stringp)
         "string")
;; => "string"
(cl-emos '(vectorp listp stringp)
         42)
;; => nil

Of course now it's subtly different than using cl-some with the same predicate(s). But it lets you return the expensive expression's evaluated result and bind it, which seems closer to the spirit of you question.

Greg Hendershott
  • 1,493
  • 12
  • 17
6

If I understand your request OK, this is exactly what run-hook-with-args-until-success does. (There are also functions run-hook-with-args-until-failure and run-hook-with-args.)

run-hook-with-args-until-success is a built-in function in `C source
code'.

(run-hook-with-args-until-success HOOK &rest ARGS)

Run HOOK with the specified arguments ARGS.
HOOK should be a symbol, a hook variable.  The value of HOOK
may be nil, a function, or a list of functions.  Call each
function in order with arguments ARGS, stopping at the first
one that returns non-nil, and return that value.  Otherwise (if
all functions return nil, or if there are no functions to call),
return nil.

Do not use ‘make-local-variable’ to make a hook variable buffer-local.
Instead, use ‘add-hook’ and specify t for the LOCAL argument.

See the Elisp manual, node Running Hooks.

Drew
  • 77,472
  • 10
  • 114
  • 243
  • Neat, I didn't know hooks may take arguments. – wvxvw Sep 19 '15 at 21:33
  • Thanks, as additinal goal for question I like to see function name, seems that there are no any standard in Lisp practice: http://stackoverflow.com/questions/32671159/ but Elisp have some, +1 – gavenkoa Sep 20 '15 at 10:40
  • Sorry, I don't understand your "additional goal" comment. Could you elaborate? Or maybe pose a new question for it, if it is something different? – Drew Sep 20 '15 at 16:23
1

I don't know of an existing function to do this, but it's simple enough to write in plain Elisp.

(defun some-predicate (val predicates)
  (when predicates
    (or (funcall (car predicates) val)
        (some-predicate val (cdr predicates)))))

This returns t (the return value of the predicate that returns non-nil):

(some-predicate 1 '((lambda (val) (> val 2)) (lambda (val) (> val 0))))

This returns nil:

(some-predicate 1 '((lambda (val) (> val 2)) (lambda (val) (> val 1))))

Note that because it uses recursion, it could blow the stack if you have a long list of predicates.

zck
  • 9,092
  • 2
  • 33
  • 65
0

With help from https://stackoverflow.com/a/32690256/173149 there are another built-in into cl-lib alternatives which also available in CL:

;; analog for some.
(loop with value = (floor (* 10 (sin 9)))
      for pred in (list #'symbolp #'numberp)
      thereis (funcall pred value))

;; analog for every.
(loop with value = (floor (* 10 (sin 9)))
      for pred in (list #'numberp #'plusp #'evenp)
      always (funcall pred value))
gavenkoa
  • 3,452
  • 20
  • 37