Say you have a data-structure (borrowed from this question):
data Greek = Alpha | Beta | Gamma | Delta | Eta | Number Int
Now one can make it an instance of Show
by appending deriving Show
on that instruction.
Say however we wish to show Number Int
as:
instance Show Greek where
show (Number x) = show x
-- ...
The problem is that one must specify all other parts of the Greek
data as well like:
show Alpha = "Alpha"
show Beta = "Beta"
For this small example that's of course doable. But if the number of options is long, it requires a large amount of work.
I'm wondering whether it is possible to access the "default show" implementation and call it with a wildcard. For instance:
instance Show Greek where
show (Number x) = show x
show x = defaultShow x
You thus "implement" the specific patterns that differ from the default approach and the remaining patterns are resolved by the "fallback mechanism".
Something a bit similar to method overriding with a reference to super.method
in object oriented programming.
As @phg pointed above in the comment this can be also done with the help of generic-deriving:
{-# LANGUAGE DeriveGeneric #-}
module Main where
import Generics.Deriving.Base (Generic)
import Generics.Deriving.Show (GShow, gshow)
data Greek = Alpha | Beta | Gamma | Delta | Eta | Number Int
deriving (Generic)
instance GShow Greek
instance Show Greek where
show (Number n) = "n:" ++ show n
show l = gshow l
main :: IO ()
main = do
print (Number 8)
print Alpha
You can sorta accomplish this using Data and Typeable. It is a hack of course, and this example only works for "enumerated" types as in your example.
I'm sure we could get more elaborate with how we do this, but to cover your given example:
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Data
import Data.Typeable
data Greek = Alpha | Beta | Gamma | Delta | Eta | Number Int
deriving (Data,Typeable)
instance Show Greek where
show Number n = show n
show x = show $ toConstr x
This approach as I've implemented it cannot handle nested data structures or anything else remotely fancy, but again, this is an ugly hack. If you really must use this approach you can dig around in the Data.Data
package I'm sure you could piece something together...
Here is a blog post giving a quick introduction to the packages: http://chrisdone.com/posts/data-typeable
The proper way to go about this would be to use a newtype
wrapper. I realize that this isn't the most convenient solution though, especially when using GHCi, but it incurs no additional overhead, and is less likely to break in unexpected ways as your program grows.
data Greek = Alpha | Beta | Gamma | Delta | Eta | Number Int
deriving (Show)
newtype SpecialPrint = SpecialPrint Greek
instance Show SpecialPrint where
show (SpecialPrint (Number x)) = "Number: " ++ show x
show (SpecialPrint x) = show x
main = do
print (SpecialPrint Alpha)
print (SpecialPrint $ Number 1)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With