
Clojure: `every-pred` and `some-fn` - tosh
https://lambdaisland.com/blog/2019-12-03-advent-of-parens-3-some-fn-every-pred
======
77544cec
For those that are interested, I gathered in a gist some functional
combinators I have been writing over the years.

As a personal name convention, I use '|' (the piping character) as a suffix to
name any function returning a function, which includes function combinators.
Thus the naming of these functions becomes straighforward: 'every-pred'
becomes 'and|' while 'some-fn' turns into 'or|'.

Example:

    
    
        (filter (and| pos? even?) nums)
        (filter (or|  neg? odd?)  nums)
    

More:
[https://gist.github.com/TristeFigure/acd689f3c57e840ebb9f8a6...](https://gist.github.com/TristeFigure/acd689f3c57e840ebb9f8a65a2052e49)

~~~
dimovich
Thank you for sharing this! Another useful library with "missing" functions is
Medley[0] by James Reeves.

[0]
[https://github.com/weavejester/medley](https://github.com/weavejester/medley)

------
drcode
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.

~~~
dustingetz
> 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 can extend syntax from a library and thus keep
the change-restricted surface area small since almost anything can be
implemented in a library.

I think, don't recall a smoking gun quote for this, correct me if I'm wrong.

~~~
jdminhbg
If you check his remarks from Spec-ulation
([https://www.youtube.com/watch?v=oyLBGkS5ICk](https://www.youtube.com/watch?v=oyLBGkS5ICk)),
he also thinks just plain old libraries should not remove or change
functionality, but only accrete. If you want to make a breaking change, you
should change the name of the library. You can see this philosophy in practice
with clojure.spec.alpha-2: [https://github.com/clojure/spec-
alpha2](https://github.com/clojure/spec-alpha2)

~~~
gowld
That's SemVer with the version in the name.

------
wellpast
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
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.

~~~
wellpast
It is probably true that a majority today favors static types, but I don't
think this a subjective issue __if the problem is maximizing developer
throughput over time __.

Working on statically typed code bases that model things the way you are
describing substantially increases the effort and time it takes to iterate. So
while you may prefer them (per your experience or what else), there is still
the fact that this way of development is suboptimal with respect to delivery
throughput over time.

Of course this is arguable (and is a very heavily _argued_ topic) and the
common retort is "to each is own" that isn't sufficient to me.

One might prefer to work in assembly language (per experience or
predisposition) but there is still a general statement that can be made that
this is intrinsically a suboptimal way to work if delivery throughput is your
goal.

I believe that a similar claim can be made to differentiate working in static
ADT v. dynamic Map types when modeling business domains.

More food for thought. The typo problems you mentioned are solved by static
types but at what cost? And is the CBA there? _Especially_ considering that
there are other ways to "solve" the typo problem that do not come with the
heavy tax burden of statically typed ADTs.

~~~
jjnoakes
In my experience static types increase my development velocity.

I can make changes and find many bugs at compile time without writing tests. I
still write tests of course but I have to write fewer, and I rarely waste time
fixing trivial things that raise errors at runtime.

It is also much quicker for me to navigate the code. I can find definitions
for identifiers instantly and get my mental model refreshed easily every time
I switch contexts.

I use dynamic languages too, and I find myself spending more time on things
that static languages do for me.

------
FPGAhacker
> 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
Manning’s “Clojure. The essential reference”[1] has quite good coverage of
these functions.

[1] [https://www.manning.com/books/clojure-the-essential-
referenc...](https://www.manning.com/books/clojure-the-essential-reference)

------
alexott
For interested - this blog is a part of Planet Clojure:
[http://planet.clojure.in/](http://planet.clojure.in/)

