* Re: How to mapcar or across a list? [not found] <mailman.6968.1436991281.904.help-gnu-emacs@gnu.org> @ 2015-07-15 20:45 ` Pascal J. Bourguignon 2015-07-15 21:02 ` Marcin Borkowski 2015-07-15 23:56 ` Barry Margolin 1 sibling, 1 reply; 10+ messages in thread From: Pascal J. Bourguignon @ 2015-07-15 20:45 UTC (permalink / raw) To: help-gnu-emacs Marcin Borkowski <mbork@mbork.pl> writes: > Hi there, > > so here's my problem: I have a list of Boolean values, and I want to > `mapcar' an `or' across it (IOW, I want to test whether at least one of > them is true). Of course, (apply #'or my-list) does not work. Of > course, I can (cl-reduce (lambda (x y) (or x y)) my-list) -- but is > there a better method? > > BTW, my-list doesn't really exist: it is a result of `mapcar'ing > a function taking some value and yielding a Boolean value, so bonus > points if the method does not process the whole list. It's too late, lisp is not a lazy language. > (Note: I just noticed that my-list is in fact sorted so that all true > values (if any) will occur at the beginning anyway, so I can just test > the first one. This means that my problem is purely academic, though > still interesting, I guess.) First you want to reduce a list of booleans to a single value, so what makes you thing that mapcar is the right too for that? There's the word "map" in "mapcar", didn't you notice? map reduce x1 --> r1 x1 -\ x2 --> r2 x2 --+-> r x3 --> r3 x3 -/ Also, mapcar allocates a new list of same length as the original list for the result, so it is costly. At least, you could consider mapc. With mapc (or mapcar) you could perform your task with some cl magic: (require 'cl) (setf lexical-binding t) (defun* or-all (list) (mapc (lambda (element) (when element (return-from or-all t))) list) nil) (defun* and-all (list) (mapc (lambda (element) (unless element (return-from and-all nil))) list) t) (or-all '(nil nil nil)) --> nil (or-all '(nil t nil)) --> t (and-all '(t t t)) --> t (and-all '(t nil t)) --> nil But I fail to see how it's better than: (defun* or-all (list) (reduce (lambda (a b) (or a b)) list)) (defun* and-all (list) (reduce (lambda (a b) (and a b)) list)) or than just: (some 'identity '(nil nil nil)) --> nil (some 'identity '(nil t nil)) --> t (some 'identity '(t t t )) --> t (every 'identity '(nil nil nil)) --> nil (every 'identity '(t nil t )) --> nil (every 'identity '(t t t )) --> t There are also the negations: (notevery 'identity '(nil nil nil)) --> t (notevery 'identity '(nil t nil)) --> t (notevery 'identity '(t t t )) --> nil (notany 'identity '(nil nil nil)) --> t (notany 'identity '(t nil t )) --> nil (notany 'identity '(t t t )) --> nil And since your booleans are computed by a function with mapcar, you could avoid computing this function for all the elements of the original list, and you could avoid allocating the temporary list by having some call this function: So instead of: (reduce (lambda (a b) (or a b)) (mapcar 'complex-and-lengthy-predicate list)) use: (some 'complex-and-lengthy-predicate list) For example: (some (lambda (x) (print x) (evenp x)) '(1 2 3 5 7 9 11)) prints: 1 2 --> t Learn more about Common Lisp: http://www.lispworks.com/documentation/HyperSpec/Front/ http://cliki.net/ -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: How to mapcar or across a list? 2015-07-15 20:45 ` How to mapcar or across a list? Pascal J. Bourguignon @ 2015-07-15 21:02 ` Marcin Borkowski 0 siblings, 0 replies; 10+ messages in thread From: Marcin Borkowski @ 2015-07-15 21:02 UTC (permalink / raw) To: help-gnu-emacs On 2015-07-15, at 22:45, Pascal J. Bourguignon <pjb@informatimago.com> wrote: > Marcin Borkowski <mbork@mbork.pl> writes: > >> Hi there, >> >> so here's my problem: I have a list of Boolean values, and I want to >> `mapcar' an `or' across it (IOW, I want to test whether at least one of >> them is true). Of course, (apply #'or my-list) does not work. Of >> course, I can (cl-reduce (lambda (x y) (or x y)) my-list) -- but is >> there a better method? >> >> BTW, my-list doesn't really exist: it is a result of `mapcar'ing >> a function taking some value and yielding a Boolean value, so bonus >> points if the method does not process the whole list. > > It's too late, lisp is not a lazy language. Well, *after* I mapcar then it's too late, but your own answer (below) shows that mapcar itself is not necessary (as I suspected). >> (Note: I just noticed that my-list is in fact sorted so that all true >> values (if any) will occur at the beginning anyway, so I can just test >> the first one. This means that my problem is purely academic, though >> still interesting, I guess.) > > First you want to reduce a list of booleans to a single value, so what > makes you thing that mapcar is the right too for that? There's the word > "map" in "mapcar", didn't you notice? My bad, you're right, of course. > map reduce > > x1 --> r1 x1 -\ > x2 --> r2 x2 --+-> r > x3 --> r3 x3 -/ Please, do not shame a mathematician. I hope notany (pun intended;-)) of my students will read this... > Also, mapcar allocates a new list of same length as the original list > for the result, so it is costly. At least, you could consider mapc. True. > With mapc (or mapcar) you could perform your task with some cl magic: > > (require 'cl) > (setf lexical-binding t) > > (defun* or-all (list) > (mapc (lambda (element) > (when element > (return-from or-all t))) > list) > nil) > > (defun* and-all (list) > (mapc (lambda (element) > (unless element > (return-from and-all nil))) > list) > t) > > (or-all '(nil nil nil)) --> nil > (or-all '(nil t nil)) --> t > > (and-all '(t t t)) --> t > (and-all '(t nil t)) --> nil > > > But I fail to see how it's better than: > > (defun* or-all (list) > (reduce (lambda (a b) (or a b)) list)) > > (defun* and-all (list) > (reduce (lambda (a b) (and a b)) list)) Of course, but - as I expected - someone already felt that there should be a more elegant way, and hence the abstraction called `some', `every' etc. > or than just: > > (some 'identity '(nil nil nil)) --> nil > (some 'identity '(nil t nil)) --> t > (some 'identity '(t t t )) --> t > > (every 'identity '(nil nil nil)) --> nil > (every 'identity '(t nil t )) --> nil > (every 'identity '(t t t )) --> t > > There are also the negations: > > (notevery 'identity '(nil nil nil)) --> t > (notevery 'identity '(nil t nil)) --> t > (notevery 'identity '(t t t )) --> nil > > (notany 'identity '(nil nil nil)) --> t > (notany 'identity '(t nil t )) --> nil > (notany 'identity '(t t t )) --> nil > > And since your booleans are computed by a function with mapcar, you > could avoid computing this function for all the elements of the original > list, and you could avoid allocating the temporary list by having some > call this function: > > > So instead of: > > (reduce (lambda (a b) (or a b)) > (mapcar 'complex-and-lengthy-predicate list)) > > use: > > (some 'complex-and-lengthy-predicate list) How cool. Again: I felt that something like that should exist, so I'm not surprised that it actually does. > For example: > (some (lambda (x) (print x) (evenp x)) '(1 2 3 5 7 9 11)) > prints: > 1 > > 2 > --> t > > > Learn more about Common Lisp: > http://www.lispworks.com/documentation/HyperSpec/Front/ > http://cliki.net/ Well, maybe I should. I have a bunch of students who want to study CL, I should be able to help them;-). (I read parts of the Cl spec, most of "Practical Common Lisp" and small parts of "On Lisp", but that was a few years ago...) Thanks again, -- Marcin Borkowski http://octd.wmi.amu.edu.pl/en/Marcin_Borkowski Faculty of Mathematics and Computer Science Adam Mickiewicz University ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: How to mapcar or across a list? [not found] <mailman.6968.1436991281.904.help-gnu-emacs@gnu.org> 2015-07-15 20:45 ` How to mapcar or across a list? Pascal J. Bourguignon @ 2015-07-15 23:56 ` Barry Margolin 1 sibling, 0 replies; 10+ messages in thread From: Barry Margolin @ 2015-07-15 23:56 UTC (permalink / raw) To: help-gnu-emacs In article <mailman.6968.1436991281.904.help-gnu-emacs@gnu.org>, Marcin Borkowski <mbork@mbork.pl> wrote: > Hi there, > > so here's my problem: I have a list of Boolean values, and I want to > `mapcar' an `or' across it (IOW, I want to test whether at least one of > them is true). Of course, (apply #'or my-list) does not work. Of > course, I can (cl-reduce (lambda (x y) (or x y)) my-list) -- but is > there a better method? "mapcar" is not the right metaphor. It's for running the same function separately on each element of a list, not for combining elements. -- Barry Margolin, barmar@alum.mit.edu Arlington, MA *** PLEASE post questions in newsgroups, not directly to me *** ^ permalink raw reply [flat|nested] 10+ messages in thread
* How to mapcar or across a list? @ 2015-07-15 20:14 Marcin Borkowski 2015-07-15 20:42 ` Rasmus ` (3 more replies) 0 siblings, 4 replies; 10+ messages in thread From: Marcin Borkowski @ 2015-07-15 20:14 UTC (permalink / raw) To: Help Gnu Emacs mailing list Hi there, so here's my problem: I have a list of Boolean values, and I want to `mapcar' an `or' across it (IOW, I want to test whether at least one of them is true). Of course, (apply #'or my-list) does not work. Of course, I can (cl-reduce (lambda (x y) (or x y)) my-list) -- but is there a better method? BTW, my-list doesn't really exist: it is a result of `mapcar'ing a function taking some value and yielding a Boolean value, so bonus points if the method does not process the whole list. (Note: I just noticed that my-list is in fact sorted so that all true values (if any) will occur at the beginning anyway, so I can just test the first one. This means that my problem is purely academic, though still interesting, I guess.) Best, -- Marcin Borkowski http://octd.wmi.amu.edu.pl/en/Marcin_Borkowski Faculty of Mathematics and Computer Science Adam Mickiewicz University ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: How to mapcar or across a list? 2015-07-15 20:14 Marcin Borkowski @ 2015-07-15 20:42 ` Rasmus 2015-07-15 20:55 ` Marcin Borkowski 2015-07-15 22:21 ` Emanuel Berg ` (2 subsequent siblings) 3 siblings, 1 reply; 10+ messages in thread From: Rasmus @ 2015-07-15 20:42 UTC (permalink / raw) To: help-gnu-emacs Marcin Borkowski <mbork@mbork.pl> writes: > Hi there, > > so here's my problem: I have a list of Boolean values, and I want to > `mapcar' an `or' across it (IOW, I want to test whether at least one of > them is true). Of course, (apply #'or my-list) does not work. Of > course, I can (cl-reduce (lambda (x y) (or x y)) my-list) -- but is > there a better method? > > BTW, my-list doesn't really exist: it is a result of `mapcar'ing > a function taking some value and yielding a Boolean value, so bonus > points if the method does not process the whole list. Does cl-some and cl-every fit the bill? Rasmus -- Vote for Dick Taid in an election near you! ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: How to mapcar or across a list? 2015-07-15 20:42 ` Rasmus @ 2015-07-15 20:55 ` Marcin Borkowski 0 siblings, 0 replies; 10+ messages in thread From: Marcin Borkowski @ 2015-07-15 20:55 UTC (permalink / raw) To: help-gnu-emacs On 2015-07-15, at 22:42, Rasmus <rasmus@gmx.us> wrote: > Marcin Borkowski <mbork@mbork.pl> writes: > >> Hi there, >> >> so here's my problem: I have a list of Boolean values, and I want to >> `mapcar' an `or' across it (IOW, I want to test whether at least one of >> them is true). Of course, (apply #'or my-list) does not work. Of >> course, I can (cl-reduce (lambda (x y) (or x y)) my-list) -- but is >> there a better method? >> >> BTW, my-list doesn't really exist: it is a result of `mapcar'ing >> a function taking some value and yielding a Boolean value, so bonus >> points if the method does not process the whole list. > > Does cl-some and cl-every fit the bill? Ha. Their only drawback is that I didn't know about them... > Rasmus Thanks! -- Marcin Borkowski http://octd.wmi.amu.edu.pl/en/Marcin_Borkowski Faculty of Mathematics and Computer Science Adam Mickiewicz University ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: How to mapcar or across a list? 2015-07-15 20:14 Marcin Borkowski 2015-07-15 20:42 ` Rasmus @ 2015-07-15 22:21 ` Emanuel Berg 2015-07-15 22:21 ` John Mastro [not found] ` <mailman.6977.1436998965.904.help-gnu-emacs@gnu.org> 3 siblings, 0 replies; 10+ messages in thread From: Emanuel Berg @ 2015-07-15 22:21 UTC (permalink / raw) To: help-gnu-emacs Marcin Borkowski <mbork@mbork.pl> writes: > so here's my problem: I have a list of Boolean > values, and I want to `mapcar' an `or' across it > (IOW, I want to test whether at least one of them is > true). Of course, (apply #'or my-list) does not > work. Of course, I can (cl-reduce (lambda (x y) (or > x y)) my-list) -- but is there a better method? "Better" I don't know, but how about using your new-found skills with the backquote? (`or' itself should be used, of course.) (setq boolean-list-1 '(t nil nil nil t nil nil)) (setq boolean-list-2 '(nil nil nil nil nil nil nil)) (eval `(or ,@boolean-list-1)) ; t (eval `(or ,@boolean-list-2)) ; nil > BTW, my-list doesn't really exist: it is a result of > `mapcar'ing a function taking some value and > yielding a Boolean value, so bonus points if the > method does not process the whole list. Check. It is a consequence of using `or', which is "short circuited" as it is called in other languages, perhaps in Lisp too - I've read "conditional evaluation" as well in AI books, but perhaps that is something else. Anyway: (or t undefined) ; t (or undefined t) ; error: (void-variable undefined) in eval To verify, append "undefined" to "boolean-list-1" (no error) - but, there will be an error (the same as above) if appended to "boolean-list-2"! ... I suppose now would be a good time for you to hand over them points! -- underground experts united http://user.it.uu.se/~embe8573 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: How to mapcar or across a list? 2015-07-15 20:14 Marcin Borkowski 2015-07-15 20:42 ` Rasmus 2015-07-15 22:21 ` Emanuel Berg @ 2015-07-15 22:21 ` John Mastro [not found] ` <mailman.6977.1436998965.904.help-gnu-emacs@gnu.org> 3 siblings, 0 replies; 10+ messages in thread From: John Mastro @ 2015-07-15 22:21 UTC (permalink / raw) To: Help Gnu Emacs mailing list > so here's my problem: I have a list of Boolean values, and I want to > `mapcar' an `or' across it (IOW, I want to test whether at least one of > them is true). Of course, (apply #'or my-list) does not work. Of > course, I can (cl-reduce (lambda (x y) (or x y)) my-list) -- but is > there a better method? You've already gotten good answers from others but, for the sake of one more option, you could also accomplish this with `cl-loop' (which, of course, some love and some hate). It would end up looking something like: (cl-loop for item in list thereis (your-predicate item)) If the predicate would be `(not (null item))', you can drop it entirely (as you would expect): (cl-loop for item in list thereis item) -- john ^ permalink raw reply [flat|nested] 10+ messages in thread
[parent not found: <mailman.6977.1436998965.904.help-gnu-emacs@gnu.org>]
* Re: How to mapcar or across a list? [not found] ` <mailman.6977.1436998965.904.help-gnu-emacs@gnu.org> @ 2015-07-15 22:28 ` Pascal J. Bourguignon 2015-07-15 22:36 ` Emanuel Berg 0 siblings, 1 reply; 10+ messages in thread From: Pascal J. Bourguignon @ 2015-07-15 22:28 UTC (permalink / raw) To: help-gnu-emacs Emanuel Berg <embe8573@student.uu.se> writes: > Marcin Borkowski <mbork@mbork.pl> writes: > >> so here's my problem: I have a list of Boolean >> values, and I want to `mapcar' an `or' across it >> (IOW, I want to test whether at least one of them is >> true). Of course, (apply #'or my-list) does not >> work. Of course, I can (cl-reduce (lambda (x y) (or >> x y)) my-list) -- but is there a better method? > > "Better" I don't know, but how about using your > new-found skills with the backquote? (`or' itself > should be used, of course.) > > (setq boolean-list-1 '(t nil nil nil t nil nil)) > (setq boolean-list-2 '(nil nil nil nil nil nil nil)) > > (eval `(or ,@boolean-list-1)) ; t > (eval `(or ,@boolean-list-2)) ; nil Nope. It's always a bad idea to use eval, because eval evalutes in the nil environment, not in the local lexical envrionment. Your example works because those lists are literal, but then you don't need or to know the answer. In pratice, translating: (flet ((some-complex-predicate (x) …)) (let ((some-data (generate-some-data))) (some (function some-complex-predicate) some-data))) to: (flet ((some-complex-predicate (x) …)) (let ((some-data (generate-some-data))) (eval `(or ,@(mapcar (lambda (data) `(some-complex-predicate ',data)) some-data))))) fails lamentably. It is also very slow, since it makes you build a new list, and it makes you interpret, or worse, compile, some new code! -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: How to mapcar or across a list? 2015-07-15 22:28 ` Pascal J. Bourguignon @ 2015-07-15 22:36 ` Emanuel Berg 0 siblings, 0 replies; 10+ messages in thread From: Emanuel Berg @ 2015-07-15 22:36 UTC (permalink / raw) To: help-gnu-emacs "Pascal J. Bourguignon" <pjb@informatimago.com> writes: > It's always a bad idea to use eval, because eval > evalutes in the nil environment, not in the local > lexical envrionment. > > Your example works because those lists are literal, > but then you don't need or to know the answer. OK, what about doing `cl-dolist' which we also had in a recent discussion? (cl-dolist (b boolean-list-1) (when b (cl-return t))) ; t (cl-dolist (b boolean-list-2) (when b (cl-return t))) ; nil -- underground experts united http://user.it.uu.se/~embe8573 ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2015-07-15 23:56 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- [not found] <mailman.6968.1436991281.904.help-gnu-emacs@gnu.org> 2015-07-15 20:45 ` How to mapcar or across a list? Pascal J. Bourguignon 2015-07-15 21:02 ` Marcin Borkowski 2015-07-15 23:56 ` Barry Margolin 2015-07-15 20:14 Marcin Borkowski 2015-07-15 20:42 ` Rasmus 2015-07-15 20:55 ` Marcin Borkowski 2015-07-15 22:21 ` Emanuel Berg 2015-07-15 22:21 ` John Mastro [not found] ` <mailman.6977.1436998965.904.help-gnu-emacs@gnu.org> 2015-07-15 22:28 ` Pascal J. Bourguignon 2015-07-15 22:36 ` Emanuel Berg
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).