
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.