是否可以定义我自己的 Show 类并重用 TextShow 和 Prelude.Show 的实例?

luo*_*990 2 haskell typeclass

我正在尝试定义自己的Show名为 的类MyShow,并希望从TextShow 和 中“窃取”实例Prelude.Show,并且如果两者都存在,则更喜欢前一个。

我尝试了以下操作(showbPrec事情被简化以集中精力):

{-# 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)
Run Code Online (Sandbox Code Playgroud)

但我被告知不允许重复实例声明Show,那么有什么方法可以定义我自己的实例并重用其他人的实例吗?

Ice*_*ack 6

这不会让您分支到哪个实例可用,这违背了开放世界的假设,即添加新实例不应改变程序的行为。有多种方法可以进行这种分支,一种方法是编译器插件IfSat,但这不是正常的方法。

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
Run Code Online (Sandbox Code Playgroud)

使用这些新类型,您可以派生实例以供您MyShow使用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
Run Code Online (Sandbox Code Playgroud)