4 ms·
Unix pipelines are indeed beautiful, especially when you consider its similarity to Haskell's monadic I/O: http://okmij.org/ftp/Computation/monadic-shell.html h
by CalmStorm 6y ago
Unix pipelines are indeed beautiful, especially when you consider its similarity to Haskell's monadic I/O:
http://okmij.org/ftp/Computation/monadic-shell.html http://okmij.org/ftp/Computation/monadic-shell.html
Unix pipelines actually helped me make sense of Haskell's monad.
- AnimalMuppet 6y agoCould you be more specific? I don't get it.
- CalmStorm 6y agoIn Unix: a; b # Execute command b after a. The result of a is not used by b. In Haskell: a >> b # Run function b after a. The result of a is not used by b. In Unix: a | b # Execute command b after a. The result of a is used by b. In Haskell: a >>= b # Run function b after a. The result of a is used by b.
- cnity 6y agoNitpick, sort of, but in unix, a | b executes a and b in parallel, not sequentially. This somewhat complicates the analogy with programming. They're more like functions operating on a data stream. Edit: I might be misinterpreting your use of "execute _after_". You may not mean "after the completion of a" but instead "operating on the results of a, asynchronously" in which case, apologies.
- msla 6y agoIt helps if you avoid the syntactic sugar of do-notation: main = getArgs >>= processData >>= displayData main is in the IO monad. The >>= function takes a value wrapped in a monad and a function which accepts a value and returns a value wrapped in the same type of monad, and returns the same monad-wrapped value the function did. It can be used as an infix operator because Haskell allows that if you specify precedence, in which case its left side is the first argument (the value-in-a-monad) and its right side is the second argument (the function). The (imaginary) function getArgs takes no arguments and returns a list of command-line arguments wrapped in an IO monad. The first >>= takes that list and feeds it into the function on its right, processData, which accepts it and returns some other value in an IO monad, which the third >>= accepts and feeds into displayData, which accepts it and returns nothing (or, technically, IO (), the unit (empty) value wrapped in an IO monad) which is main's return value. See? Everything is still function application, but the mental model becomes feeding data through a pipeline of functions, each of which operates on the data and passes it along.
- AnimalMuppet 6y agoThanks. That's helpful.
- thesz 6y agoPipelines are function composition, not monads. For pipelines to be monadic, their structure must be able to change depending on the result on the part of pipeline. The type of binding operator hints at it: (>>=) :: m a -> (a -> m b) -> m b. The second argument receives result of first computation and computes the way overall result (m b) will be computed. As for program composition, I would like to add gstreamer to the mix: it allows for DAG communication between programs.