在 GADT 上定义类型 class 实例
defining type class instance on 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
是依赖于类型参数 foo
的 GADT,其类型为 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))
时接受它?
我认为这是一种自然的方式:
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
可以通过存在量化来避免额外的类型class:
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
考虑以下代码
{-# 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
是依赖于类型参数 foo
的 GADT,其类型为 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))
时接受它?
我认为这是一种自然的方式:
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
可以通过存在量化来避免额外的类型class:
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