
Higher-order Shell - r11t
http://conway.rutgers.edu/~ccshan/wiki/blog/posts/Higher-order_shell/
======
nixme
Zsh already has the first program built-in using the = expansion. For his
example it would be:

    
    
      xdvi =(curl http://www.diku.dk/~andrzej/papers/RC.dvi)
    

Yet another reason why you should switch to zsh _today_ :)

More about expansions in zsh:
<http://zsh.sourceforge.net/Doc/Release/zsh_13.html>

~~~
wendroid
Tom Duff's rc shell has the same construct

    
    
        xdvi <{curl http://www.diku.dk/~andrzej/papers/RC.dvi}
    

Another reason why you should have changed to rc shell 10 years ago

<http://doc.cat-v.org/plan_9/4th_edition/papers/rc>

------
tel
I like the attempt to use Haskell type signatures as terse documentation. For
'tmp' it pretty nearly tells the whole story (especially rewritten flipping
the first two arguments as below)

    
    
      tmp :: (FilePath -> IO ()) -> (Stream -> IO ())
      Transforms file-accepting function to work on an input stream.
    

'keep' is a bit more ambiguous, but I think it's more clear if you write it
instead as

    
    
      keep :: IO a -> IO [()]
    

which has parallels to 'repeat :: a -> [a]' and suggests that the first action
will be "kept" and repeated periodically, throwing away the output. At this
point, you have to guess when it repeats, but since you provide 'keep' no
further information, blocking until files update is a pretty logical guess.

~~~
olliesaunders
I got the suspicion that Haskell notation was used because he'd written those
commands in Haskell; could be wrong though.

~~~
tel
No, I thought so at first as well, but later realized that he was doing it
totally for documentation's purposes (well, and impact).

~~~
jrockway
I don't think some of the things he writes, like "MonadIO m => m () -> IO ()"
are generally possible, for example. There are specific instances of MonadIO
(ErrorT, etc.) that have a function that does that, but MonadIO itself only
has the liftIO function, which is "MonadIO m => IO a -> m a".

~~~
tel
Good call. I agree in disagreeing with his type for 'keep'. I think he was
aiming at the idea of "any computation which is liftable to an IO computation"
instead of "computation which can be evaluated within an IO context".

In my opinion, since 'keep' takes a function which is, in general, fully
capable of any effectful action, it necessarily is of the type

    
    
      keep :: IO a -> ...
    

but since it's roughly ignoring any potential return 'a', yet still evaluating
the function repeatedly, the best type is something like

    
    
      keep :: IO a -> IO [()]

~~~
jrockway
I think he actually meant "MonadIO m => m a -> m a".

Anyway, if I were going to use Haskell-style type signatures in an article
about shell scripts written in Perl, I would probably skip the whole typeclass
and monad concept, and just say something like:

    
    
       keep :: Action -> Action
    

This doesn't say much about the infinite nature of the process, unfortunately,
but modeling effects as though they are pure functions just gets you into
trouble anyway. His textual description is much more natural and easier to
understand.

Anyway, I like articles that combine both Perl and Haskell :) They make me
feel less insane.

------
there
while not helpful for his examples, some programs that don't grok "-" as a
shortcut to read data from stdin (or a pipe) are ok being passed "/dev/stdin"
as the filename.

~~~
wendroid
or /fd/0 or /dev/fd/0 (depending on OS)

------
gnosis
_"Surely I was not the first to write the following two higher-order
programs..."_

He's right. There is, for example, _rc_ (the Plan 9 shell, made in 1989).

The following is from section 10, "Pipeline branching" of: <http://plan9.bell-
labs.com/sys/doc/rc.html>

_" < or > followed by a command in braces causes the command to be run with
its standard output or input attached to a pipe. The parent command (cmp in
the example) is started with the other end of the pipe attached to some file
descriptor or other, and with an argument that will connect to the pipe when
opened (e.g., /dev/fd/6)."_

~~~
cgs1019
I believe the rc feature exemplified in the link is actually equivalent to
that used in the this bash idiom:

$ cmp <(old) <(new)

(only the braces differ). The author of the article describes a case in which
the command in question (unlike cmp) cannot read its input from a pipe such as
this, namely xdvi. So for instance

$ cat file.dvi | xdvi

or

$ xdvi <(file.dvi)

would not work due to the nature of xdvi, but one could use

$ cat file.dvi | tmp xdvi

as a shorthand for

$ cat file.dvi > /tmp/blah $ xdvi /tmp/blah $ rm /tmp/blah

(of course using cat this way would be stupid, but suppose that the file data
is going to stdout via a command such as curl, as in the article, and it
becomes non-trivial).

I really like the characterization of these commands as sort of second-order
and I like the 2 new ones offered here (although I try not to get too addicted
to command line features that aren't going to be around when I'm hopping from
server to server).

