

Chaining vs. Nesting - frankus
http://frankschmitt.org/2010/01/chaining-v-nesting

======
camccann
Function composition and currying seem like a more natural translation to me.

Or you can think of it like this:

netstat_n >>= grep "tcp" >>= flip awk 5 >>= sort >>= uniq_c >>= sort_n

See also: <http://okmij.org/ftp/Computation/monadic-shell.html>

~~~
samstokes
Glad someone posted that link, or I was going to :)

Pipes and method chaining "feel" the same. They're both _expressions_ , but
with the property that you could rewrite them as what looks like a series of
_statements_ without changing the semantics (although possibly changing the
efficiency). e.g.

    
    
        usual_suspects.director.surname
    

has the same value ("Singer") as

    
    
        person = usual_suspects.director
        surname = person.surname
        surname
    

and

    
    
        cat /etc/passwd | grep root | cut -d: -f6
    

outputs the same thing (root's home directory) as

    
    
       cat /etc/passwd > tmp1
       grep root tmp1 > tmp2
       cut -d: -f6 tmp2 > tmp3
       cat tmp3
    

They feel the same because they're both monadic (at least when the chained
methods or piped processes behave in certain 'normal' ways). '.' (the method
invocation operator) and '|' (the pipe operator) are monadic combinators, just
like Haskell's >>= and F#'s |>. And a monadic combinator is just a
generalisation of function composition.

Monads are going to become a lot more important in the next few years, as
programming languages get more expressive and capable of more abstraction.
LINQ in C# and VB is a great example - while it looks like they've baked in
language support for lots of concepts (querying databases and XML, for data
parallelism and for event-driven programming), what they've really done is
recognised that those are all forms of monadic computation, baked in language
support for _one_ thing (monadic expressions), then implemented those concepts
as _libraries_ that any user could have written. (Erik Meijer and Brian
Beckman on MS's Channel 9 explain this really nicely.)

------
frognibble
Here's the example from the article written using the Clojure thread macro:

(-> netstat_n (grep "tcp") (awk 5) sort uniq_c sort_n print)

------
Avshalom
I remember first running into this point with
<http://xahlee.org/UnixResource_dir/writ/notations.html> and I'm sure Slava or
somebody has pointed out that in postfix languages like Factor and Forth
everything is essentially chained which very naturally leads to a function
composition style. And that despite the "reverse" nature of RPN it often ends
up being "forward", witness in Factor REPL actually being REPL instead of
L(P(E(R))).

------
voxcogitatio
I've seen an interesting way to do method chaining in haskell: The '$'
operator: Basically it's a low-priority right-associative binary operator that
applies the function to the left to everything to the right.

Using the example from the article, one could do it as:

sort -n $ uniq -n $ sort $ awk '{ print $5}' $ grep tcp $ netstat -n

I.e essentially the same but in reverse order.

~~~
eru
($) helps to avoid some parens. The (.) is more common to change functions,
and closely related. ($) does not really compose functions, it is function
application and right associative.

Your example would rather read something close to

    
    
      sort -n . uniq -n . sort . awk '{ print $5}' . grep tcp . netstat -n
    

(And `$ argument' at the end, if there was one.)

~~~
samstokes
($) is actually the least interesting operator in the world :) But as you say,
its parsing precedence makes it useful (because it lets you skip parens).

What I like is how ($) generalises to (<$>) for applicative functors, so you
can write

    
    
       succ $ 5                -- -> 6
       succ <$> Nothing        -- -> Nothing
       succ <$> Just 5         -- -> Just 6
       succ <$> [1, 2, 3]      -- -> [2, 3, 4]
    

Who needs "for" loops? :)

~~~
eru
I agree. Though I'd say id or const or even less interesting than ($).

------
DenisM
I don't think ternary expression is ugly by itself, it's only ugly if
parameters themselves are chains beacuse then you're back to having a tree.
Which is the fundamental problem - chaining is not good for branches, so any
branches send you back to nesting. On the higher level theproblem is that you
are trying to express a tree as a list - ain't going to work.

Haskel side-steps this problem in a neat way - you can take advantage of
delayed evaluation and give names to both arguments of the ternary expression
so each individual piece looks linear. So your "tree" is broken down line by
line:

    
    
      x=...
      y=...
      z=f?x:y
      

which is as neat and easy to read as a chain, but is more powerful because it
can express a tree.

Once could enforce this sort of reader-friendly style by forbidding
expressions in ternary operators.

------
pvg
Comparing a model in which the contract is 'everything is a stream of
characters' to function application and composition in just about any
programming language seems more than a little clueless.

~~~
camccann
_"I think there's a connection. Certainly in the early days of Unix, pipes
facilitated function composition on the command line. You could take an input,
perform some transformation on it, and then pipe the output into another
program. (...) [The mathematical approach of function composition is] exactly
what I mean. (...) I think [that mathematical formalism] was right there from
the start. Doug McIlroy, at least in my book, deserves the credit for pipes.
He thought like a mathematician and I think he had this connection right from
the start. I think of the Unix command line as a prototypical functional
language."_

\-- from an interview with Alfred Aho, one of the creators of AWK

[http://books.google.com/books?id=yB1WwURwBUQC&lpg=PT120&...](http://books.google.com/books?id=yB1WwURwBUQC&lpg=PT120&ots=-BUH9ErkdB&pg=PT120#v=onepage&q=&f=false)

~~~
pvg
It's 2010, not the 'early days of Unix'. Yes there is a connection, a useful
one, if you are sitting in front of a PDP-8.

[http://groups.google.com/group/comp.lang.functional/msg/8476...](http://groups.google.com/group/comp.lang.functional/msg/84763c6d9185178b?dmode=source&hl=en)

<http://regex.info/blog/2006-09-15/247#comment-3085>

~~~
blasdel
I don't think unix pipes in the shell would be very useful to someone sitting
in front of a PDP-8

The machine's panel switches are enough of a pain when programming in the
absolute -- give a shell user a teletype at least!

~~~
pvg
A bit of a hyperbole, granted. Pipes -> any kind of vaguely modern runtime
(clojure? srsly?) is a profoundly nonsensical comparison though.

~~~
barrkel
I don't understand your hostility to pipes. It seems to be based on the fact
that they were invented some time ago? On the contrary, the soundness of an
idea famous enough to be known today is probably positively correlated with
how old it is.

Pipes are a combination of dataflow programming and monadic computation, and
are naturally parallelizable, functional and generally pipe processes don't
share mutable state. All these concepts are highly relevant to modern
programming.

~~~
Daniel_Newby
pvg's dislike seems to be that pipes transfer a stream of octets with no
inherent syntax or semantics. That means every program needs baroque options
to impose structure, which is difficult to create, maintain, and debug. Also
brittle.

~~~
barrkel
And on the other hand, text streams are easy to work with, because ad-hoc
tools can be written to work with them, rather than having to wrestle with
strongly typed libraries and being constrained to languages compatible with
the libraries that define those types. Imagine a web written using CORBA RPCs
over rendering APIs, rather than HTML over HTTP.

You can argue that HTML has inherent syntax and semantics, but of course
server and client can have slightly different ideas, and it all still works,
mostly. The same is largely true of shell programming using pipes: different
stages in the pipe expect certain formats, for regular expression or field
extraction, and format pasting together, etc. The format is easy to eyeball
and easy to test on the shell REPL, so in practice the problems aren't large.

