[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)