Daniel Wagner 的答案的一个开放变体将使用 aTypeFamily
让实现该类的每种类型指定它需要的上下文。
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ScopedTypeVariables #-}
import GHC.Exts (Constraint)
import Data.Proxy
data Dict c where
Dict :: c => Dict c
该类允许每种类型指定Ctx a
该类型需要的附加约束。该cdict
函数强制上下文遵循C
并提供一种方法来获取底层 Ctx
s 而无需将它们包含在Ctx
例如产品中。
class C a where
type Ctx a :: Constraint
cdict :: Proxy a -> CDict a
然后ACDict
是 a Dict
,它既包含约束,也包含类型需要的C a
任何附加上下文Ctx a
a
type CDict a = Dict (C a, Ctx a)
该Int
实例不需要任何额外的上下文
instance C Int where
type Ctx Int = ()
cdict _ = Dict
元组实例同时需要C a
和C b
instance (C a, C b) => C (a, b) where
type Ctx (a, b) = (C a, C b)
cdict _ = Dict
我们可以写fstCDict
元组。
fstCDict :: forall a b. CDict (a, b) -> CDict a
fstCDict Dict = case cdict (Proxy :: Proxy a) of Dict -> Dict
不正确的实例
如果我们尝试编写一个不正确的实例C
来神奇地召唤Show
实例
instance (C a) => C (Maybe a) where
type Ctx (Maybe a) = (C a, Show a)
cdict _ = Dict
它会导致编译器错误
Could not deduce (Show a) arising from a use of `Dict'
from the context (C a)
bound by the instance declaration ...
Possible fix:
add (Show a) to the context of the instance declaration
In the expression: Dict
In an equation for `cdict': cdict _ = Dict
In the instance declaration for `C (Maybe a)'