Arrows: definition of pure & arr

After having played with some packages that use arrows, and after having read the very nice "programming with arrows" paper I wanted to build some of my own. Strangely my code did not work, even the simplest function got stuck in an infinite loop or gave a stack overflow. I quickly noticed I made a really stupid mistake, I forget to implement "arr"! However, the compiler did not give a warning on this. So I wandered how it was possible that the Arrow package had a default implementation for something so specific as arr? The code revealed the following: -- | Lift a function to an arrow: you must define either this -- or 'pure'. arr :: (b -> c) -> a b c arr = pure -- | A synonym for 'arr': you must define one or other of them. pure :: (b -> c) -> a b c pure = arr Ah, so the default implementation of arr is pure... and vice versa... This feels like rather incorrect to me, but my feelings are based on imperative background knowledge, so this might be totally correct design in Haskell. Why not force people to implement arr and leave just pure as the synonym? And if pure is really a synonym for arr, what does it do inside the Arrow type class? Does it ever make sense to have a different implementation for arr and pure? Thanks for any help, Peter

On 16 Feb 2008, at 11:40 PM, Peter Verswyvelen wrote:
After having played with some packages that use arrows, and after having read the very nice "programming with arrows" paper I wanted to build some of my own.
Strangely my code did not work, even the simplest function got stuck in an infinite loop or gave a stack overflow.
I quickly noticed I made a really stupid mistake, I forget to implement "arr"! However, the compiler did not give a warning on this. So I wandered how it was possible that the Arrow package had a default implementation for something so specific as arr?
The code revealed the following:
-- | Lift a function to an arrow: you must define either this -- or 'pure'. arr :: (b -> c) -> a b c arr = pure
-- | A synonym for 'arr': you must define one or other of them. pure :: (b -> c) -> a b c pure = arr Ah, so the default implementation of arr is pure... and vice versa...
This feels like rather incorrect to me, but my feelings are based on imperative background knowledge, so this might be totally correct design in Haskell.
Why not force people to implement arr and leave just pure as the synonym? And if pure is really a synonym for arr, what does it do inside the Arrow type class? Does it ever make sense to have a different implementation for arr and pure?
No; the equations arr = pure and pure = arr are laws for the class. (This is true in general for default methods). Note that this situation --- where leaving the default methods in place gives rise to an infinite loop --- is quite common; it occurs for the classes Eq and Ord, as well, for example. This example is admittedly kind of silly, but I'm sure someone has a passionate attachment to one or both names, so requiring definitions to use one or the other would be controversial. jcc

On Sun, Feb 17, 2008 at 12:00:43AM -0800, Jonathan Cast wrote:
arr = pure pure = arr [...] This example is admittedly kind of silly, but I'm sure someone has a passionate attachment to one or both names, so requiring definitions to use one or the other would be controversial.
Perhaps not. I used the name pure for arr in the Fun of Programming paper, because Richard Bird preferred that name, but it hasn't caught on, and now the same name is used in the Applicative class. So perhaps it should be removed from Arrow.

I don't get why the name isn't "arrow" instead of "arr"... Arr reminds me of pirates, "arrrrrrrhh" ;-) I guess "first" was chosen because "fst" was already taken, but then it would be logical to choose "arrow" instead of "arr" ;-) Ross Paterson wrote:
On Sun, Feb 17, 2008 at 12:00:43AM -0800, Jonathan Cast wrote:
arr = pure pure = arr [...] This example is admittedly kind of silly, but I'm sure someone has a passionate attachment to one or both names, so requiring definitions to use one or the other would be controversial.
Perhaps not. I used the name pure for arr in the Fun of Programming paper, because Richard Bird preferred that name, but it hasn't caught on, and now the same name is used in the Applicative class. So perhaps it should be removed from Arrow. _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Am Sonntag, 17. Februar 2008 14:32 schrieb Peter Verswyvelen:
I don't get why the name isn't "arrow" instead of "arr"... Arr reminds me of pirates, "arrrrrrrhh" ;-) I guess "first" was chosen because "fst" was already taken, but then it would be logical to choose "arrow" instead of "arr" ;-)
arr has two problems in my opinion. First, it is an unneccessarily truncated name. Is it really so difficult to type two letters more? Second, it doesn’t describe its purpose very well. Okay, it constructs an arrow. But (>>>) and first do this as well. pure makes much more sense to me, since it says that it constructs *pure* arrows. If you look at Grapfruit’s source code, you probably won’t find any occurences of arr (but you’ll find Arrow.pure rather often). Best wishes, Wolfgang

Ah, "pure" stands for "pure arrow". I found this confusing since I consider all functions in Haskell (except unsafeXXX and maybe IO) to be "pure". So pureArrow would be good but is so loooong ;-) Actually, if you look at the way OO programmers design code, they usually choose long descriptive names, like "FindElementByName". Most Haskell people seem more math oriented and use very short names, like "fst" and "snd" (which are a bit better than the old "car" and "cdr"). Now in the end, once you get used to a name, it doesn't matter does it? But when I show typical Haskell code to object-oriented friends of mine, they get scared because it looks like math, with all the symbols and short names. But if I show code like render $ solid (rectangle (position 100 100) (size 400 50)) `inColor` red `over` line (position 50 50) (position 150 150) `withLineSize` 4 `inColor` blue and compare that to what this would like when using C++ (or C# with WPF...), they go... wow... The only question they tend to ask is "what does the $ and `` do?". And if I tell them I designed this mini-language myself in Haskell in a few lines of code without lexing and yaccing, they can hardly believe it. Mmm, maybe this is a good one for "Why functional programming matters", but for the experienced Haskellers, the above DSL stuff is probably too obvious. So even if I don't know much of Haskell yet, the ability to write these small DSLs so compactly and elegantly is what one of things I really like about the language. E.g. for my students, I wrote a little "3D vector math" exercise generator in a couple of hours. This tool generates algebraic exercises and shows the solutions step by step by performing simplification, using indented pretty printing. I would never have been able to do that in C++ or C# in such a short time and so compactly, even though I have +15 years more experience with the latter language. But in Haskell, even though I hardly know the language, it was "easy". I now want to use GTK2HS to generate PDFs from these exercises that also shows step-by-step geometrical solutions (but that's work in progress ;) PS: Wolfgang also seems to use nice names in Grapefruit for his types, e.g. act :: PlainCircuit (IO output) output createPlainCircuit :: PlainCircuit input output -> input -> IO (output, IO ()) instead of act :: PlainCircuit (IO a) a mkPlainCircuit :: PlainCircuit a b -> a -> IO (b, IO ()) What is the general "style guide" regarding this?
-----Original Message----- From: haskell-cafe-bounces@haskell.org [mailto:haskell-cafe- bounces@haskell.org] On Behalf Of Wolfgang Jeltsch Sent: Tuesday, February 19, 2008 11:29 AM To: haskell-cafe@haskell.org Subject: Re: [Haskell-cafe] Arrows: definition of pure & arr
Am Sonntag, 17. Februar 2008 14:32 schrieb Peter Verswyvelen:
I don't get why the name isn't "arrow" instead of "arr"... Arr reminds me of pirates, "arrrrrrrhh" ;-) I guess "first" was chosen because "fst" was already taken, but then it would be logical to choose "arrow" instead of "arr" ;-)
arr has two problems in my opinion. First, it is an unneccessarily truncated name. Is it really so difficult to type two letters more? Second, it doesn’t describe its purpose very well. Okay, it constructs an arrow. But (>>>) and first do this as well. pure makes much more sense to me, since it says that it constructs *pure* arrows.
If you look at Grapfruit’s source code, you probably won’t find any occurences of arr (but you’ll find Arrow.pure rather often).
Best wishes, Wolfgang _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- No virus found in this incoming message. Checked by AVG Free Edition. Version: 7.5.516 / Virus Database: 269.20.7/1286 - Release Date: 2/18/2008 6:49 PM

On Tue, 19 Feb 2008, Peter Verswyvelen wrote:
But when I show typical Haskell code to object-oriented friends of mine, they get scared because it looks like math, with all the symbols and short names.
They will feel like a C programmer looking at C++ code, wondering how the heck an output stream can be left shifted by a number using << . :-)

Exactly. And that must be one of the reasons the Java designers said "no" to operator overloading? That kind of programmers just don't like operators I guess. But we do :-) Although I would prefer nice math symbols and layout instead of the :~> ASCII art. Thielemann wrote:
On Tue, 19 Feb 2008, Peter Verswyvelen wrote:
But when I show typical Haskell code to object-oriented friends of mine, they get scared because it looks like math, with all the symbols and short names.
They will feel like a C programmer looking at C++ code, wondering how the heck an output stream can be left shifted by a number using << . :-)

Am Dienstag, 19. Februar 2008 19:37 schrieb Peter Verswyvelen:
Exactly. And that must be one of the reasons the Java designers said "no" to operator overloading? That kind of programmers just don't like operators I guess. But we do :-) Although I would prefer nice math symbols and layout instead of the :~> ASCII art.
lhs2TeX at least gives you nice math symbols when typesetting source code. Do you know this tool already? It’s brilliant, IMO. Best wishes, Wolfgang

On Feb 19, 2008 8:04 AM, Peter Verswyvelen
Actually, if you look at the way OO programmers design code, they usually choose long descriptive names, like "FindElementByName". Most Haskell people seem more math oriented and use very short names, like "fst" and "snd" (which are a bit better than the old "car" and "cdr"). Now in the end, once you get used to a name, it doesn't matter does it?
I also think this comes from better IDE support. When I'm coding in C#, I choose longer method, class, and property names because Visual Studio frees me from having to type the entire thing - Intellisense does most of the work. When I am coding in PHP or Haskell, with poor IDE support, I tend for shorter. I think a secondary influence comes from the need to typeset code in journals and books. Even if you don't actually publish your code, the people who have written the existing papers and tutorials did, and that influence the style you learn. Justin

Am Dienstag, 19. Februar 2008 17:04 schrieben Sie:
PS: Wolfgang also seems to use nice names in Grapefruit for his types, e.g.
act :: PlainCircuit (IO output) output createPlainCircuit :: PlainCircuit input output -> input -> IO (output,IO ())
instead of
act :: PlainCircuit (IO a) a mkPlainCircuit :: PlainCircuit a b -> a -> IO (b, IO ())
Whereby I have to add that I use create now instead of createPlainCircuit since in case of ambiguity you can use qualification like in PlainCircuit.create. I think, this is nicer because PlainCircuit.create is “more structured” than createPlainCircuit where everything is put into a single parameter. I’m also in the process of shortening the names for type variables since in conference papers you cannot use names that long (because otherwise you quickly overrun the available width) and I don’t want to have too many differences between papers and actual source code. However, I still don’t like single-letter names like a and b.
[…]
Best wishes, Wolfgang

Wolfgang Jeltsch wrote:
I’m also in the process of shortening the names for type variables since in conference papers you cannot use names that long (because otherwise you quickly overrun the available width) and I don’t want to have too many differences between papers and actual source code. However, I still don’t like single-letter names like a and b.
I like them if the type variables are really completely arbitrary types, like in map :: (a->b) -> [a] -> [b]. Using longer and more descriptive names here would (IMHO) be a mistake, as there is nothing specific about them. Similar on the value level, a definition like map f (x:xs) = f x : map f xs is (IMO) rather /easier/ to understand than anything using longer and more descriptive names, as, again, what x stands for is completely irrelevant here. I'd like to mention in passing that according to Dijkstra, when we develop an abstraction, it is important to (at least temporarily) forget what the symbols originally stood for, that is, before we abstracted them out of the context in which they originally appeared. The advantage is that without 'intuition' (about what the symbols 'mean') we have nothing left to follow but logic, which (supposedly) leads to a clearer understanding of the abstraction in itself, which in turn leads to shorter and more concise proofs, i.e. programs. That said, there are many situations where the type variables are linked by constraints and additional type (e.g. class method) signatures. In this case, mnemonic names can be a great help to understanding. In the example given, I'd use one-letter abbreviations of teh longer names, i.e. create :: PlainCircuit i o -> i -> IO (o, IO ()) Cheers Ben
participants (7)
-
Ben Franksen
-
Henning Thielemann
-
Jonathan Cast
-
Justin Bailey
-
Peter Verswyvelen
-
Ross Paterson
-
Wolfgang Jeltsch