views:

243

answers:

4

Lets say I have the following:

data Greek = Alpha | Beta | Gamma | Phi deriving Show

I want to use the default showing of all items except Beta, which I want to say "two".

Can I do this?

+2  A: 

As far as I know, you can't. The deriving mechanism doesn't support anyway to alter or extend the derived instances.

MtnViewMark
+13  A: 

deriving Show uses the standard instanciating mechanism (simply returning the definition). If you want any special things, you will have to instanciate it manually:

data Greek = Alpha | Beta | Gamma | Phi

instance Show Greek
    where
        show Alpha = "Alpha"
        show Beta  = "2"
        show Gamma = "Gamma"
        show Phi   = "Phi"
poke
+6  A: 

Not that this is entirely satisfactory, but you could do:

data Greek = Alpha | Beta | Gamma | Phi
    deriving (Show)

showGreek Beta = "2"
showGreek x = show x

And use showGreek instead of show. If you needed a real show instance (in my code I find that I need this less than beginners tend to think), you could do the rather cumbersome:

newtype Greek' = Greek' Greek
instance Show Greek' where
    show (Greek' g) = showGreek g

If it were my code, I'd just stick with showGreek.

A nice rule of thumb I use is that the Show and Read instances are Haskell-generated only. If show doesn't produce valid Haskell code, it shouldn't be in a Show instance.

luqui
That's not correct. Show is not meant to produce Haskell code, it's meant to return a string representation of a given data type. In that context, as long as Show and Read are working correctly with each other, there is really no problem to define anything what you want with it. Also using a new `showGreek` function doesn't really help, as the instantiation is meant to provide some abstract level that all data types can work with.
poke
poke, I would be more inclined to accept your claim about the intent of Show if you would provide a reference.As far as the level of abstraction, you are correct. You can't `showGreek` with functions that accept a constraint like Show a =>, only ones that take an HOF for showing. Still, in my practice, which I admit is not the same as yours, it is less of a problem than it would seem. If you run into it, `Greek'` should do. And if you don't accept the `Greek'`, solution, then I suppose you will have to accept this as a limitation of Haskell or switch to some other language :-P.
luqui
+3  A: 

Some of the other suggestions work great in your particular example, and I would suggest to use those.

But in a more general case you might want to use datatype-generic programming.

Using generic programming, you can write functions that work on multiple data types, i.e. functions that do the same for every data type. Examples of such functions are show and == (this is the reason those can be derived in GHC).

This is an example using the regular library:

{-# LANGUAGE TemplateHaskell, EmptyDataDecls, TypeFamilies #-}

import Generics.Regular
import qualified Generics.Regular.Functions.Show as G

data Greek = Alpha | Beta | Gamma | Phi

-- These two lines are all that is needed to use
-- Regulars generic functions on the 'Greek' data type.
$(deriveAll ''Greek "PFGreek")
type instance PF Greek = PFGreek

-- Manual written instance for 'Show'
instance Show Greek where
  show Beta = "Two"
  show x    = G.show x -- Use Regulars 'show' for the boring parts

To be honest, I don't really like the output from Regulars show function (it throws in an extra set of parentheses). But this might be a good starting point for writing your own generic functions.

Tom Lokhorst