In most functional languages, going back to ISWIM,
let State = … in
let State = …(State)… in …
let State = …(State)… in …
let State = …(State)… in …
is all you need. Each of these introduces a new
variable, which is only visible after ‘in’,
not between ‘=’ and ‘in’.
In LFE you would probably want to use let* rather than let.
Coming at this from a Haskell perspective,
I find the idea of “hiding the plumbing” attractive.
But I find the idea that there is a single combinator
that is appropriate for the majority of cases where there
is plumbing to be hidden absurd.
I remind readers that the “|>” operator in that spelling
comes from a functional language in which it is NOT
special syntax but a perfectly ordinary operator needing
no special machinery and in that language is one of several
such operators.
I’ve always been a great believer in trying to work with a
language the way it “wants” to go rather than fighting to
use it as if it were some other language. Very well,
Erlang functions are NOT curried and Erlang does NOT admit
user-defined operators. It does have parse transforms,
which are very heavyweight indeed, and not to be used lightly.
Erlang doesn’t really want to be a higher-order language at
all, and for the first few years it wasn’t one.
If you often write code that would be clearer in Elixir or
LFE, what the heck is wrong with using Elixir or LFE?
Not that code like this would be clearer in Elixir.
I find long chains of |> unreadable.
If you have compelling reasons for using Erlang specifically,
then I think it’s time to start treating “I wish I had |>” as
a code smell. I am happy with S0 S1 S2. By the time I get to
S3 I’m starting to get nervous. If I ever reach S10 it’s time
to burn what I’m writing to the ground and restructure it.
Patient: It hurts when I do .
Doctor: Ah. I see the problem. Don’t do .
Sometimes it helps to look at the rest of the code.
Perhaps there is a combination of updates that is needed
in more than one place that can be abstracted out?
If there is one update that must happen before another,
perhaps that combination should be separated out and the
constraint enforced by hiding the component updates?
I’m also coming at this from a Smalltalk point of view
(and I appreciate the reasoning behind “Joe hates OO”).
In a Smalltalk program I would regard a long block of
messages sent to the same object as
(a) a worrisome indication of coupling (the caller
“knows too much” about the object’s states)
(b) a sign that there’s a missing abstraction in the
interface of the object.
From an OO perspective, if you have an object in state
A and you want to get it into state B, you don’t force
it through an intricate sequence of state changes,
you give it some sort of description of state B and ask
it to change the state itself. The functional analogue
should I hope be clear.
We need examples with semantics and context.