Why is the no tuple syntax for sum types

Protuct types have this nice tuple syntax (a,Char,Int),(a,'c',1). Why is there no syntax like this for Sum types (a|Char|Int),(||1). This would be very usefull for some more explicit error handling. I.E. You have a library that has errors. Error1, .. ErrorN. Currently there are only two ways of making a function that can throw Error3 and Error8. Use 'Dynamic' typed Exceptions or make a general Error type that is the sum of all Errors. In both cases it is not clear from the type of the function what Errors can occur. With sumTuples you could just return (Result|Error3|Error8). Also, I guess I'm just one of those people who occasionally confuse Left and Right :) Silvio Frischknecht

On 30/07/2015 at 17:00:54 +0200, Silvio Frischknecht wrote:
You have a library that has errors.
Error1, .. ErrorN.
Currently there are only two ways of making a function that can throw Error3 and Error8.
Use 'Dynamic' typed Exceptions or make a general Error type that is the sum of all Errors. In both cases it is not clear from the type of the function what Errors can occur.
With sumTuples you could just return (Result|Error3|Error8).
I doubt whether this would work so well for errors, as I think we would want to be able to combine the values of fallible terms such as to combine the possible errors associatively and commutatively, and these sum tuples would not. The non-associativity of product tuples sometimes bites me already in other use cases. That said, I sometimes thought this myself, tho with other syntax: (a;b;c)

I doubt whether this would work so well for errors, as I think we would want to be able to combine the values of fallible terms such as to combine the possible errors associatively and commutatively, and these sum tuples would not. The non-associativity of product tuples sometimes bites me already in other use cases.
Yeah I agree tuples are not very nice to work with because you can't recurse over them. I guess it would be cool to have them internally represented similar to this. http://stackoverflow.com/a/25609890/1117884 But even without this, tuples are useful and I think sum tuples would be similarly useful. Doing things explicitly/manually is not always a bad thing. Silvio

For sum types you need a way to construct them and pattern match them. Without a way to _name_ them, it would probably look like this: showError :: (Result | Error3 | Error8) -> String showError (result ||) = "no error" showError (| error3 |) = "error3: " ++ show error3 showError (|| error8 |) = "error8: " ++ show error8 It's not the most readable code, so I'd generally avoid using it for anything greater than 3 (same applies to tuples). It also suffers the same flaw as tuples: no way to extend them easily. Imagine adding a new error: you have to edit _all_ of the patterns: showError :: (Result | Error3 | Error8 | Error11 ) -> String showError (result |||) = "no error" showError (| error3 ||) = "error3: " ++ show error3 showError (|| error8 |) = "error8: " ++ show error8 showError (||| error11 ) = "error11: " ++ show error11 Extensible records and variants might be able to solve these problems, but that's a rabbit-hole of its own though.

For sum types you need a way to construct them and pattern match them. Without a way to _name_ them, it would probably look like this:
showError :: (Result | Error3 | Error8) -> String showError (result ||) = "no error" showError (| error3 |) = "error3: " ++ show error3 showError (|| error8 |) = "error8: " ++ show error8
It's not the most readable code, so I'd generally avoid using it for anything greater than 3 (same applies to tuples).
I doubt that functions usually cause more than one or two different errors. Unless you count undefined, asyncronous ... But you don't want those in your type anyway (too verbose).
It also suffers the same flaw as tuples: no way to extend them easily. Imagine adding a new error: you have to edit _all_ of the patterns:
showError :: (Result | Error3 | Error8 | Error11 ) -> String showError (result |||) = "no error" showError (| error3 ||) = "error3: " ++ show error3 showError (|| error8 |) = "error8: " ++ show error8 showError (||| error11 ) = "error11: " ++ show error11
Extensible records and variants might be able to solve these problems, but that's a rabbit-hole of its own though.
Yes of course, but wouldn't you still agree that tuples are useful. So would sum tuples be. Additionally, tuple like structures can easily be simulated using type operators data a :' b = a :' b However, the pattern matching for even a 3-way sum type using Either will be a nightmare. And I see no way of simulating this without using Template Haskell. type ... a = a `Either` Int `Either` Char Left (Right int) ??? or Right (Left int) ??? Silvio

FWIW there's already a somewhat extensible way to do this with singletons, as shown here http://lpaste.net/137724. Could be made somewhat nicer with pattern synonyms as well. It does at least solver the pattern matching issue of nested Eithers. Silvio Frischknecht wrote
For sum types you need a way to construct them and pattern match them. Without a way to _name_ them, it would probably look like this:
showError :: (Result | Error3 | Error8) -> String showError (result ||) = "no error" showError (| error3 |) = "error3: " ++ show error3 showError (|| error8 |) = "error8: " ++ show error8
It's not the most readable code, so I'd generally avoid using it for anything greater than 3 (same applies to tuples).
I doubt that functions usually cause more than one or two different errors. Unless you count undefined, asyncronous ... But you don't want those in your type anyway (too verbose).
It also suffers the same flaw as tuples: no way to extend them easily. Imagine adding a new error: you have to edit _all_ of the patterns:
showError :: (Result | Error3 | Error8 | Error11 ) -> String showError (result |||) = "no error" showError (| error3 ||) = "error3: " ++ show error3 showError (|| error8 |) = "error8: " ++ show error8 showError (||| error11 ) = "error11: " ++ show error11
Extensible records and variants might be able to solve these problems, but that's a rabbit-hole of its own though.
Yes of course, but wouldn't you still agree that tuples are useful. So would sum tuples be.
Additionally, tuple like structures can easily be simulated using type operators
data a :' b = a :' b
However, the pattern matching for even a 3-way sum type using Either will be a nightmare. And I see no way of simulating this without using Template Haskell.
type ... a = a `Either` Int `Either` Char
Left (Right int) ???
or
Right (Left int) ???
Silvio _______________________________________________ Haskell-Cafe mailing list
Haskell-Cafe@
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
-- View this message in context: http://haskell.1045720.n5.nabble.com/Why-is-the-no-tuple-syntax-for-sum-type... Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.

For sum types you need a way to construct them and pattern match them. Without a way to _name_ them, it would probably look like this:
showError :: (Result | Error3 | Error8) -> String showError (result ||) = "no error" showError (| error3 |) = "error3: " ++ show error3 showError (|| error8 |) = "error8: " ++ show error8
It's not the most readable code, so I'd generally avoid using it for anything greater than 3 (same applies to tuples). This approach misses the essence of sum type tuples, which is
On 2015-07-31 18:44, Phil Ruffwind wrote: positional. It needs to be something like showError :: (Result | Error3 | Error) -> String showError = case of result -> "no error" | error3 -> "error3: " ++ show error3 | error3 -> "error8: " ++ show error8 This is just to illustrate the overall structure that's needed. I don't think think the above "|" syntax would ever fit into Haskell, because it would be confused with pattern guards.

I'm a little puzzled by all of this, having learned ML before there was such a thing as Standard ML. Anonymous sums, with inl, inr, outl, outr and so on are one thing I was very happy to see the back of. This sudden enthusiasm for them strikes me as being like a sudden enthusiasm for punched cards, paper tape, or PL/I.

@Scott Turner This actually works surprisingly well with Either showError :: (Result `Either` Error3 `Either` Error) -> String showError = `mapSum3` (result -> "no error" ,error3 -> "error3: " ++ show error3 ,error3 -> "error8: " ++ show error8 ) mapSum3 :: (x `Either` y `Either` z) -> (x->a,y->a,z->a) -> a But sum tuples would look cooler still :)
I'm a little puzzled by all of this, having learned ML before there was such a thing as Standard ML. Anonymous sums, with inl, inr, outl, outr and so on are one thing I was very happy to see the back of. This sudden enthusiasm for them strikes me as being like a sudden enthusiasm for punched cards, paper tape, or PL/I.
Either (and to some lesser extent Maybe) are an anonymous sum type and it is used all the time. I'm just saying it does not have the ideal syntax. P.S. The (a||) really conflicts with operators but (a;;) might actually still be possible.

On 2015-08-03 06:07 PM, Richard A. O'Keefe wrote:
This sudden enthusiasm for them strikes me as being like a sudden enthusiasm for punched cards, paper tape, or PL/I.
Oh! Punch cards can represent sum types (use different hole positions to indicate different variants), and tapes can represent tuple types! On the bright side, I haven't found a use of PL/I.
participants (7)
-
Albert Y. C. Lai
-
htebalaka
-
M Farkas-Dyck
-
Phil Ruffwind
-
Richard A. O'Keefe
-
Scott Turner
-
Silvio Frischknecht