从约束适用于产品的事实证明约束适用于产品的组件
Prove that a constraint holds for a component of a product from the fact it holds for the product
我有一个 class C
,其中包含一种类型和元组的实例。
class C a
instance C Int
instance (C a, C b) => C (a, b)
使用正常的 Dict
GADT 捕获约束
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ConstraintKinds #-}
data Dict c where
Dict :: c => Dict c
是否可以从C (a, b)
证明C a
?
fstDict :: Dict (C (a, b)) -> Dict (C a)
fstDict Dict = ???
我怀疑直接的答案是 "no",因为 fstDict Dict = Dict
还不够,而且几乎没有其他可能性。有什么方法可以更改 C
以便可以从对产品的约束中恢复对产品组件的约束?
我可能不正确地试图完成与 the most closely related question 相同的事情,但是我可以奢侈地要求类别的一端或两端获得 Dict
。
data DSL a b where
DSL :: (Dict C a -> DSL' a b) -> DSL a b
data DSL' a b where
DSL' :: (C a, C b) => ... -> DSL' a b
一种方法是将所有祖先词典存储在您的 Dict
类型中:
data CDict a where
IntDict :: C Int => CDict Int
PairDict :: C (a, b) => CDict a -> CDict b -> CDict (a, b)
fstCDict :: CDict (a, b) -> CDict a
fstCDict (PairDict fst snd) = fst
缺点是您必须使 CDict
类型反映实例的结构。
的开放变体将使用 TypeFamily
让每个实现 class 的类型指定它需要的上下文。
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ScopedTypeVariables #-}
import GHC.Exts (Constraint)
import Data.Proxy
data Dict c where
Dict :: c => Dict c
class 允许每个类型指定该类型需要的附加约束 Ctx a
。 cdict
函数强制上下文遵循 C
并提供了一种获取基础 Ctx
的方法,而无需将它们包含在 Ctx
中,例如产品。
class C a where
type Ctx a :: Constraint
cdict :: Proxy a -> CDict a
A CDict
是一个 Dict
,它包含约束 C a
以及类型 a
需要的任何其他上下文 Ctx 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)'
我有一个 class C
,其中包含一种类型和元组的实例。
class C a
instance C Int
instance (C a, C b) => C (a, b)
使用正常的 Dict
GADT 捕获约束
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ConstraintKinds #-}
data Dict c where
Dict :: c => Dict c
是否可以从C (a, b)
证明C a
?
fstDict :: Dict (C (a, b)) -> Dict (C a)
fstDict Dict = ???
我怀疑直接的答案是 "no",因为 fstDict Dict = Dict
还不够,而且几乎没有其他可能性。有什么方法可以更改 C
以便可以从对产品的约束中恢复对产品组件的约束?
我可能不正确地试图完成与 the most closely related question 相同的事情,但是我可以奢侈地要求类别的一端或两端获得 Dict
。
data DSL a b where
DSL :: (Dict C a -> DSL' a b) -> DSL a b
data DSL' a b where
DSL' :: (C a, C b) => ... -> DSL' a b
一种方法是将所有祖先词典存储在您的 Dict
类型中:
data CDict a where
IntDict :: C Int => CDict Int
PairDict :: C (a, b) => CDict a -> CDict b -> CDict (a, b)
fstCDict :: CDict (a, b) -> CDict a
fstCDict (PairDict fst snd) = fst
缺点是您必须使 CDict
类型反映实例的结构。
TypeFamily
让每个实现 class 的类型指定它需要的上下文。
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ScopedTypeVariables #-}
import GHC.Exts (Constraint)
import Data.Proxy
data Dict c where
Dict :: c => Dict c
class 允许每个类型指定该类型需要的附加约束 Ctx a
。 cdict
函数强制上下文遵循 C
并提供了一种获取基础 Ctx
的方法,而无需将它们包含在 Ctx
中,例如产品。
class C a where
type Ctx a :: Constraint
cdict :: Proxy a -> CDict a
A CDict
是一个 Dict
,它包含约束 C a
以及类型 a
需要的任何其他上下文 Ctx 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)'