At 2002-05-24 13:40, Wolfgang Jeltsch wrote:
Now, I have a type which would fit wonderfully into the Arrow concept if arrows wouldn't be expected to have a first operator.
...then it's not an Arrow. It sounds like it might be one of these, however: class Compositor comp where { identity :: comp a a; compose :: comp b c -> comp a b -> comp a c; }; I'm not sure if 'Compositor' is a good name for it, or what.
Parser arrow. And there is also a meaningful definition for pure (arr). pure f just has to be a parser which reads exactly one token, applies f to it and outputs the resulting value. The problem is that there seems to be no appropriate definition for first. That's why, in my opinion, it would be very good to have only the
Can't you have a parser that reads in one token tuple, and apply another parser to the first part of it only? Otherwise, perhaps you could have classes like this: class (Compositor arrow) => Semiarrow arrow where { arr :: (p -> q) -> arrow p q; }; class (Semiarrow arrow) => Arrow arrow where { arrFirst :: arrow p q -> arrow (p,r) (q,r); }; -- Ashley Yakeley, Seattle WA
Wolfgang Jeltsch wrote: | Now, I have a type which would fit wonderfully into | the Arrow concept if arrows wouldn't be expected to | have a first operator. Ashley Yakeley replied: | ...then it's not an Arrow. Might I remind you that an arrow (as defined in category theory) only requires identy and composition to be defined and satisfying some laws? In particular, an arrow does not have to have the operations "arr" and "first". There are many types which would fit nicely in an arrow framework, but do not because of the demand of these operators, here are two examples: * Isomorphisms, are nice arrows: type Iso a b = (a -> b, b -> a) but of course not all functions have an appropriate inverse, so arr cannot be defined. * Stream processors (from Fudgets) are nice arrows: data SP a b = Get (a -> SP a b) | Put a (SP a b) | Nil But the first operator assumes that the product type associated with this arrow must be Haskell's product (,), but in fact a sum type would make a much nicer product. The reason why John chose to lay out the arrow library as it is (I think) is because of: * Simplicity; if you are too general then you get lots of painful classes all over the place. * Sufficiency; all examples he considered in his paper fit into the current framework. It is not clear if the design of the arrow library should be redone just because some particular examples do not fit in. After all, there are many examples of monads (Sets for example) which can not be made instance of the current monad class in Haskell. Regards, /Koen. -- Koen Claessen http://www.cs.chalmers.se/~koen Chalmers University, Gothenburg, Sweden.
On Sat, 25 May 2002, Koen Claessen wrote:
There are many types which would fit nicely in an arrow framework, but do not because of the demand of these operators, here are two examples:
* Isomorphisms, are nice arrows:
type Iso a b = (a -> b, b -> a)
but of course not all functions have an appropriate inverse, so arr cannot be defined.
* Stream processors (from Fudgets) are nice arrows:
data SP a b = Get (a -> SP a b) | Put a (SP a b) | Nil
But the first operator assumes that the product type associated with this arrow must be Haskell's product (,), but in fact a sum type would make a much nicer product.
The reason why John chose to lay out the arrow library as it is (I think) is because of:
* Simplicity; if you are too general then you get lots of painful classes all over the place.
* Sufficiency; all examples he considered in his paper fit into the current framework.
It is not clear if the design of the arrow library should be redone just because some particular examples do not fit in. After all, there are many examples of monads (Sets for example) which can not be made instance of the current monad class in Haskell.
Regards, /Koen.
Exactly. The other reason is that I was dubious that one can do very much WITH an arrow that doesn't have first. It's all very well to be able to make various types into instances, but if the combinators aren't then useful, then you've suffered extra complexity in the class structure for nothing. This is a compromise, of course, and I could be persuaded that it would be better to split the Arrow class -- but only if the new instances can then be USED in a useful way. John
On Saturday, 2002-05-25, 13:25, CEST John Hughes wrote:
On Sat, 25 May 2002, Koen Claessen wrote:
There are many types which would fit nicely in an arrow framework, but do not because of the demand of these operators, here are two examples:
* Isomorphisms, are nice arrows:
type Iso a b = (a -> b, b -> a)
but of course not all functions have an appropriate inverse, so arr cannot be defined.
* Stream processors (from Fudgets) are nice arrows:
data SP a b = Get (a -> SP a b) | Put a (SP a b) | Nil
But the first operator assumes that the product type associated with this arrow must be Haskell's product (,), but in fact a sum type would make a much nicer product.
The reason why John chose to lay out the arrow library as it is (I think) is because of:
* Simplicity; if you are too general then you get lots of painful classes all over the place.
* Sufficiency; all examples he considered in his paper fit into the current framework.
It is not clear if the design of the arrow library should be redone just because some particular examples do not fit in. After all, there are many examples of monads (Sets for example) which can not be made instance of the current monad class in Haskell.
Regards, /Koen.
Exactly. The other reason is that I was dubious that one can do very much WITH an arrow that doesn't have first. It's all very well to be able to make various types into instances, but if the combinators aren't then useful, then you've suffered extra complexity in the class structure for nothing.
This is a compromise, of course, and I could be persuaded that it would be better to split the Arrow class -- but only if the new instances can then be USED in a useful way.
John
Hello, one could, for instance, define an arrow-based mapping function without using first: amap :: Arrow a => (c -> d) -> a b c -> a b d amap f a = a >>> arr f I could imagine that there are at least as many uses for Arrow without first as they are for Functor. In addition, if (by excluding first) more types would be instances of Arrow, more composition and pure operations could be expressed by the "standard" functions from the Arrow class instead of individual functions for every type. Connections between operations for different types would be expressed adequately and one would gain additional clarity and consistency. And as I wrote already, a reason for having an Arrow class without first and a subclass which introduces first is that first would be handled the same way left is handled. This would, in my opinion, result in a more consistent class system. Wolfgang
Koen Claessen writes:
* Stream processors (from Fudgets) are nice arrows:
data SP a b = Get (a -> SP a b) | Put a (SP a b) | Nil
But the first operator assumes that the product type associated with this arrow must be Haskell's product (,), but in fact a sum type would make a much nicer product.
I made an attempt to parameterize the arrow type over the type that should be used to form environments. Indeed, I used the sum type for the stream processor instance of arrows. I modified Ross Paterson's preprocessor to take advantage of this generalization. Some slides about this and an implementation can be found at http://www.cse.ogi.edu/~magnus/ProdArrows/ All the best, /M
participants (5)
-
Ashley Yakeley -
John Hughes -
Koen Claessen -
Magnus Carlsson -
Wolfgang Jeltsch