Extend a Show instance to a Tuple of any size

2019-08-05 17:53发布

问题:

I want to create a new type of data with Haskell and create the related Show instances. I need to create the tuple Show instance with another delimiter than ,.

I implemented this code (with the {-# LANGUAGE FlexibleInstances #-} pragma):

newtype Data = Data Double

instance Show Data where
  show (Data dat) = show dat

instance Show (Data,Data) where
  show (Data d1,Data d2) = show d1++" "++show d2

instance Show (Data,Data,Data) where
  show (Data d1,Data d2,Data d3) = show d1++" "++show d2++" "++show d3

Is it possible to automatically extend the Show instance to tuples of any size without manually creating the instances?


Note : I'm aware I could use concat $ intersperse " " ... to intercalate things between list elements. But for many reasons I wish to use tuples rather than lists.

回答1:

How to write generic code for tuples

This is not supported directly in the language, because tuples in Haskell are all or nothing. In Idris, this would be easy, because (a,b,c) actually means (a,(b,c)). Haskell's laziness would make that representation inefficient, and in any case Haskell just has a different concept of what a tuple is. However, you can use generics to write that sort of code! I promise it will be painful.

Why what you're trying to do is a bad idea

The biggest problem is not that you are trying to make generic tuple code. The biggest problem is that your Show instances overlap the usual ones. The base libraries already export

instance (Show a, Show b) => Show (a, b)
instance (Show a, Show b, Show c) => Show (a,b,c)

etc. When figuring out whether instances overlap, you must look only on the right side of the =>. So even if your Data is not in Show, you have a problem. Haskell insists on committing to a choice of instance before even looking to the left of the arrow. By default, it does this by complaining about overlapping instances if it can't resolve the instance uniquely. If you OverlappingInstances, you might get it working, but this is not a good use case for that somewhat evil extension. If you use IncoherentInstances, it will probably work, but that is such a massively evil extension that it is much better to pretend it does not exist at all.



回答2:

Haskell provides absolutely no way to write code that's polymorphic over tuples of different sizes.

But given that all you seem to be doing is creating tuples of Data (which is really just Double), I have to ask... why not just use a list? You can easily, trivially handle lists of all possible sizes.