在GADT上定义类型类实例

时间:2018-03-20 18:16:44

标签: haskell typeclass gadt

考虑以下代码

{-# LANGUAGE DataKinds             #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE GADTs                 #-}
{-# LANGUAGE KindSignatures        #-}
{-# LANGUAGE MultiParamTypeClasses #-}

module Test where

data Nat
    = Z
    | S Nat
    deriving Show

data Test foo (n :: Nat) where
    Final :: Test foo n
    Step :: foo n -> Test foo (S n) -> Test foo n

instance Show (foo n) => Show (Test foo n) where
    show Final           = "final"
    show (Step bar step) = show bar ++ show step

其中Test是GADT,具体取决于类型参数foo,其类型为Nat -> *

上面的代码无法编译,我有以下错误

• Could not deduce (Show (foo ('S n))) arising from a use of ‘show’
  from the context: Show (foo n)
    bound by the instance declaration at src/Test.hs:18:10-42
• In the second argument of ‘(++)’, namely ‘show step’
  In the expression: show bar ++ show step
  In an equation for ‘show’:
         show (Step bar step) = show bar ++ show step
   |
20 |     show (Step bar step) = show bar ++ show step
   |                                        ^^^^^^^^^

我如何声明Show (foo n)适用于每个n,以便编译器在查找Show (foo (S n))时接受它?

1 个答案:

答案 0 :(得分:3)

我认为这是一种自然的方式:

class ShowAllNats f where showNat :: f (n :: Nat) -> String
instance ShowAllNats foo => Show (Test foo n) where
    show Final = "final"
    show (Step bar step) = showNat bar ++ show step

可以通过存在量化来避免其他类型类:

data Some f where Some :: f (n :: Nat) -> Some f
instance Show (Some foo) => Show (Test foo n) where
    show Final = "final"
    show (Step bar step) = show (Some bar) ++ show step