1

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.

ThreeFx
  • 7,250
  • 1
  • 27
  • 51
JeanJouX
  • 2,555
  • 1
  • 25
  • 37
  • 3
    No. At least not in an easy way. But you can just change the output of the ``show`` instance for tuples: ``rewrite ('(':xs) = replace "," " " $ init xs`` where ``replace`` is from [``Data.String.Utils``](https://hackage.haskell.org/package/MissingH-1.3.0.1/docs/Data-String-Utils.html). – ThreeFx Jun 03 '15 at 12:45
  • if you can live with *nested* tuples like `(1,('a',"b"))` it should be straight forward ;) – Random Dev Jun 03 '15 at 13:04
  • It sounds to me like you are looking for a pretty-printing library. Have a look on Hackage; there are several good ones (with subtle differences). – Daniel Wagner Jun 03 '15 at 21:57

2 Answers2

4

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.

MathematicalOrchid
  • 61,854
  • 19
  • 123
  • 220
  • In fact, my `Data` type will contain several kind of types (Double, Integer, String, ...). And my lists of `Data` must be coherent and have fixed size. If I use lists of lists, I will had to perform many tests to check this cohesion. List of tuples will remain simpler. – JeanJouX Jun 03 '15 at 13:16
  • 2
    @JeanJouX This kind of sounds like you could make use of [this](https://www.fpcomplete.com/user/konn/prove-your-haskell-for-great-safety/dependent-types-in-haskell). – ThreeFx Jun 03 '15 at 13:22
  • 2
    What do you mean by "coherent"? – MathematicalOrchid Jun 03 '15 at 13:27
3

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.

dfeuer
  • 48,079
  • 5
  • 63
  • 167
  • 1
    I like the somewhat vs massively evil distinction. – chi Jun 03 '15 at 15:51
  • For clarification: Are Idris' tuples isomorph to Haskell's lists? – ThreeFx Jun 03 '15 at 16:04
  • 1
    @ThreeFx, no, they're really just pairs. In Idris, tuple sytax is pure sugar, ``the (Nat `Pair` (Char `Pair` String)) (1,('2',"3"))`` gets you `(1, '2', "3") : (Nat, Char, String)`. – dfeuer Jun 03 '15 at 16:33
  • @dfeuer You're right of course, thank you. I forgot about heterogeneous collections. – ThreeFx Jun 03 '15 at 16:37