考虑以下代码
{-# 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))
时接受它?
答案 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