
On 02/16/2016 03:06 AM, Dennis Raddle wrote:
I am a Haskell beginner. I have used arrows occasionally to move 2-tuples around, but don't understand more than that.
I'm interested in know what's the connection between arrows and 2-tuples. I don't really understand most of the Control.Arrow docs, but it seems that a lot of stuff about arrows doesn't mention 2-tuples. Yet the operators (***), (&&&), first, and second seem to be common. Is there some way to explain the link?
Also, the main instance of Arrow seems to be (->). There is also something about Kleisli monads, but I don't know what those are. Is there an another big use case for arrows besides (->)? Don't worry about explaining it all, just a quick mention would be fine and I can investigate it myself.
An arrow is basically a function and it doesn't hurt to think of them that way. In mathematics, "function" means something very specific, so they needed a new name (arrow) for a thing that's a lot like a function but isn't one. You can construct some weird situations where arrows aren't very much like mathematical functions at all, but it still doesn't hurt to think of them that way. Mentally I prefer to embiggen my concept of "function" rather than give it up entirely in the new setting. You're probably already used to this: the random() "function" is not a mathematical function, but we all call it one. There's no specific connection between arrows and two-tuples. It's extremely common to use functions on two-tuples, and every function is an arrow, so the fact that all of those useful (***) and (&&&) live in Control.Arrow is a bit of a premature abstraction. Frequently you'll need to take a function f and a pair (x,y) and want to compute the pair (f x, f y). There should really be a combinator for that! But when you write one, it turns out that it works just as well for arrows. Since all functions are arrows, they just used the more general type. The Kleisli arrow/monad thing isn't wrong, it's just useless without an example. Kleisli arrows are just plain old arrows (think: functions) in a monad. Suppose I want to read a file and then print its contents to the screen. How would I do that? In pseudo-code, it's something like, -- Read a file and print its contents to the screen (putStr . readFile) "/path/to/file.txt" But here, "print" and "readFile" aren't mathematical functions, so we can't compose them! The "." operator only works on functions. It would be great if there were something that was a lot like a function but could be composed in this manner... -- Read a file and print its contents to the screen ghci> import Control.Monad ( (<=<) ) ghci> (putStr <=< readFile) "hw.txt" Hello, world! Another useful example is when you want to "automatically" concatenate a list of results. Let's write a stupid function that duplicates its argument in a list: ghci> let twice x = [x, x] ghci> twice 3 [3,3] So far so good. But now I want four things. Can I compose "twice" with itself? ghci> (twice . twice) 3 [[3,3],[3,3]] ghci> :t (twice . twice) (twice . twice) :: t -> [[t]] Crap, that's giving me a list of lists. I just want one list! By thinking of "twice" as a multi-valued function (a special type of arrow), I can get what I want: ghci> (twice <=< twice) 3 [3,3,3,3] That trick is using the Monad instance for lists, but composition in monads is done with arrows (not mathematical functions). It's put to good use in e.g. HXT where you can say "give me all children of <p> elements that live in a <div> that live in a <body>" and you only want one list back. Without that funny arrow composition, you'd be stuck with lists of lists of lists of lists...