[HN Gopher] Clojure: `every-pred` and `some-fn` ___________________________________________________________________ Clojure: `every-pred` and `some-fn` Author : tosh Score : 91 points Date : 2020-01-05 17:18 UTC (5 hours ago) (HTM) web link (lambdaisland.com) (TXT) w3m dump (lambdaisland.com) | alexott wrote: | For interested - this blog is a part of Planet Clojure: | http://planet.clojure.in/ | drcode wrote: | The thing to understand about Clojure is that its | creator/maintainer believes software tools should almost never | deprecate features. Because of this, there are a few esoteric | functions and features that were created in the language along | the way that will likely always remain in the language- The two | examples given by OP arguably fall into that category, though I'm | sure someone in this thread will attempt to argue that every-pred | & some-fn are essential features for the core language. | | Other oddities include juxt, areduce, fnil, nthnext, derive, | seque, and by now arguably the whole "ref" memory system (since | Software Transactional Memory has pretty much gone by the wayside | as a desirable programming feature) | | Of course, Rich Hickey has also been very good at deciding which | features to put into the language in the first place, so the | number of legacy oddities is pretty tiny anyway, fewer than most | languages. | tprice7 wrote: | Are there more recent features of Clojure that you think have | made every-pred and some-fn less useful? I'm curious what they | are if that is the case. | drcode wrote: | So, for the every-pred example, I'd prefer to use clojure | piping for better readability: (->> people | (filter :admin?) (filter :mod?)) | | This is admittedly a matter of taste, though. | | For the some-fn example, I would argue that the usage in OP | is a very idealized and tuned example... how often do you | really want to say "try this one predicate and if that | doesn't work, try this other one"? I only need to do that | maybe a couple of times a year (when parsing some sort of | irregular raw data) so it's rare enough that I'd prefer to | write the predicate explicitly instead of using this sort of | succinct predicate composition that could become a "head- | scratcher" at a future date. | TeMPOraL wrote: | Nice feature of doing it like in the post: | (filter (every-pred :admin? :mod?) people) | | is that a) this arguably conses less, by building only one | results list, and b) :admin? and :mod? are just regular | arguments, which means they could be replaced by data. I'm | thinking of: (let [acl [:admin? :mod?]] | (filter (apply every-pred acl) people)) | dustingetz wrote: | > Rich believes software tools should almost never deprecate | features | | This is pretty severely mis-stated | | He believes the _core_ of a dynamic programming language | (specifically the core) has a very high bar for stability in | order to avoid a number of problems that other dynamic | languages have. This intersects with a number of other ideas, | for example Lisp macros let libraries extend the language and | thus keep the change-restricted surface area small. | | I think, don't recall a smoking gun quote for this, correct me | if I'm wrong. | thom wrote: | I don't see why these are so weird, logical composition of | predicates is really common. | drcode wrote: | Hmm... I guess that's a valid point, though I would never use | them for logical composition simply because the names of | these functions really hurt readability: They are basically | higher-order versions of "and" and "or", maybe if they had | those words in their name they would be less cumbersome. | disconcision wrote: | I think 'every' and 'some' are reasonable analogues, but | the choice to make the implementations and hence their | suffixes asymmetric wrt 'truthiness handling' is confusing | to me, especially since these functions have existed | (symmetrically) for a while in various schemes under the | names 'conjoin' and 'disjoin' | drcode wrote: | I agree that I'd be far more likely to use these if they | were named "conjoin" and "disjoin". | TeMPOraL wrote: | These names are even worse. I know Clojure likes this | style, but to me, "conjoin" is just a fancy way of | writing "join" if you want another distinct symbol naming | the same, very generic concept. | | "some" and "every" create nicely readable code. "every- | pred" and "some-fn" could be called "satisfies-every" and | "satisfies-some", respectively. | disconcision wrote: | digging into the clojure core implementation, it looks | like this asymmetry originates with 'every?' versus | 'some', which test predicates against collections, the | former being boolean, and the later returning the first | non-falsy element. again, this feels a little non- | committal; it's true that the not-strictly-boolean | behavior of the disjunctive forms is handier than the | conjunctive ones, but the latter can still come in handy. | drcode wrote: | The irregular naming of "some" vs "some?" has been the | source of several tricky bugs for me in the past, and I | suspect many other Clojurians would report this as well. | FPGAhacker wrote: | > Clojure has a bunch of functions with every and some in their | names, which can be a bit confusing. In some? and some-> it | refers to a value being something other than nil, whereas in some | and some-fn it means "the first one that applies" | | I haven't used any of the "some" functions much, but it seems to | me you could read this was "the first one that is not nil" which | would be consistent. | alexott wrote: | Manning's "Clojure. The essential reference"[1] has quite good | coverage of these functions. | | [1] https://www.manning.com/books/clojure-the-essential- | referenc... | wellpast wrote: | This is great and now these functions are now square in my radar, | as well. | | As far as his example goes, this IS how you model data: | (def people [{:name "Elsie" :admin? true | :mod? true} {:name "Lin Shiwen" | :nickname "Rocky" :mod? true}]) | | Notice the lack of a "fill-in" static ADT form. No types here -- | no static types NOR no ":type" field. Instead, we say what we | know about our data items and we omit what we don't know. Just | the facts, ma'am. And then Clojure gives us the obscenely simple | tools to deal. | | It will forever confound me why some developers/PLs wish to model | data in static, inflexible, a priori structures -- given the | overtly clear development efficiency and simplicity of NOT doing | so (and not HAVING to do so.) | jjnoakes wrote: | I find one's point of view on the matter is largely colored by | one's experience. | | For example, I personally love static types. In your example I | would prefer modelling people as a list of structs, each one | with a required "name" (string), an optional "nickname" (string | option), and required boolean flags for mod and admin. | | Why would I prefer it to be that way? Because a huge number of | typos I might introduce in my project are caught before I even | try to run something. | | I've been bitten once too many times by a typo somewhere (like | looking up the "nick" property instead of "nickname") and | having the program raise an error after it's already ran for a | while. I can't stand that. | bjconlan wrote: | This can all be covered by more abstractions though via some | schema/spec/type validation process. Ide integration is the | interesting problem here (and typescript does this | beautifully) but I agree horses for courses (and experience). | I think the idea for using the keyword to hold the | nullability of a field interesting, I thought this was more | of a meta attribute in clj? In saying that I actually find | this style of keywording way easier to read. ___________________________________________________________________ (page generated 2020-01-05 23:00 UTC)