Home > Blockchain >  Is it possible to define my own Show class and reuse instances of TextShow and Prelude.Show?
Is it possible to define my own Show class and reuse instances of TextShow and Prelude.Show?

Time:08-17

I'm trying to define my own Show class named MyShow, and want to 'steal' instances from TextShow and Prelude.Show, and prefer the former one if both exists.

I tried following (showbPrec things is simplified to be focused):

{-# LANGUAGE UndecidableInstances #-}

import Data.Text (Text, pack, unpack)
import qualified Prelude as P
import qualified TextShow as T

class MyShow a where
    showText :: a -> Text

instance {-# OVERLAPPING #-} TextShow a => MyShow a where
    showText x = T.showt x

instance {-# OVERLAPPABLE #-} P.Show a => MyShow a where
    showText x = pack (P.show x)

But I'm telled that Duplicate instance declarations is not allowed, so is there any way to define my own Show and reuse instances from others?

CodePudding user response:

This won't let you branch on which instance is available, that goes against the open-world assumption where adding a new instance should not change the behaviour of your program. There are ways of doing this kind of branching, one approach is the compiler plugin IfSat but this is not the normal way of doing it.

newtype AsShow a = AsShow a

instance P.Show a => MyShow (AsShow a) where
  showText :: AsShow a -> Text
  showText (AsShow a) = pack (P.show a)

newtype AsTextShow a = AsTextShow a

instance TextShow a => MyShow (AsTextShow a) where
  showText :: AsTextShow a -> Text
  showText (AsTextShow a) = showt a

With these newtypes you can then derive instances for your MyShow using DerivingVia

{-# Language DerivingVia #-}
{-# Language StandaloneDeriving #-}

-- standalone deriving for types defined elsewhere
deriving via AsShow Int     instance MyShow Int
deriving via AsShow Integer instance MyShow Integer

data BOOL = FALSE | TRUE
  deriving
  stock P.Show

  deriving MyShow
  via AsShow BOOL
  • Related