Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Subclassing" show in Haskell?

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?

like image 302
me2 Avatar asked Mar 27 '10 14:03

me2


4 Answers

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

data Greek = Alpha | Beta | Gamma | Phi

instance Show Greek
    where
        show Alpha = "Alpha"
        show Beta  = "2"
        show Gamma = "Gamma"
        show Phi   = "Phi"
like image 50
poke Avatar answered Oct 21 '22 05:10

poke


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.

like image 44
luqui Avatar answered Oct 21 '22 05:10

luqui


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.

like image 31
Tom Lokhorst Avatar answered Oct 21 '22 04:10

Tom Lokhorst


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

like image 45
MtnViewMark Avatar answered Oct 21 '22 05:10

MtnViewMark