[Haskell-cafe] Why is the no tuple syntax for sum types

68 views
Skip to first unread message

Silvio Frischknecht

unread,
Jul 30, 2015, 11:01:04 AM7/30/15
to haskell-cafe
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
_______________________________________________
Haskell-Cafe mailing list
Haskel...@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

M Farkas-Dyck

unread,
Jul 30, 2015, 11:17:12 AM7/30/15
to Silvio Frischknecht, haskell-cafe
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)

Silvio Frischknecht

unread,
Jul 30, 2015, 11:35:31 AM7/30/15
to M Farkas-Dyck, haskell-cafe

> 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

Phil Ruffwind

unread,
Jul 31, 2015, 6:44:56 PM7/31/15
to Silvio Frischknecht, haskell-cafe
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.

Silvio Frischknecht

unread,
Jul 31, 2015, 10:37:06 PM7/31/15
to Phil Ruffwind, haskell-cafe
> 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

htebalaka

unread,
Aug 1, 2015, 10:40:44 AM8/1/15
to haskel...@haskell.org
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
> 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-types-tp5814499p5814758.html
Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.

Scott Turner

unread,
Aug 3, 2015, 7:45:33 AM8/3/15
to haskel...@haskell.org
On 2015-07-31 18:44, Phil Ruffwind 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).
This approach misses the essence of sum type tuples, which is
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.

Richard A. O'Keefe

unread,
Aug 3, 2015, 6:07:48 PM8/3/15
to haskell-cafe
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.

Silvio Frischknecht

unread,
Aug 5, 2015, 5:13:29 AM8/5/15
to haskel...@haskell.org
@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.

Albert Y. C. Lai

unread,
Aug 5, 2015, 11:06:16 AM8/5/15
to haskel...@haskell.org
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.
Reply all
Reply to author
Forward
0 new messages