证明产品组件的约束适用于产品的实际情况

时间:2015-01-09 02:33:56

标签: haskell typeclass gadt constraint-kinds

我有一个类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证明C (a, b)吗?

fstDict :: Dict (C (a, b)) -> Dict (C a)
fstDict Dict = ???

我怀疑答案是"不是"因为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

2 个答案:

答案 0 :(得分:1)

一种方法是将所有祖先词典存储在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类型反映你的实例的结构。

答案 1 :(得分:1)

Daniel Wagner's answer的开放变体将使用TypeFamily让实现该类的每个类型指定它所需的上下文。

{-# LANGUAGE GADTs #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ScopedTypeVariables #-}

import GHC.Exts (Constraint)
import Data.Proxy

data Dict c where
    Dict :: c => Dict c

该类允许每种类型指定类型所需的附加约束Ctx acdict函数会强制关注来自C的上下文,并提供一种方法来获取基础Ctx,而不将其包括在Ctx中,例如class C a where type Ctx a :: Constraint cdict :: Proxy a -> CDict a 。产品

CDict

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 binstance (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)'

导致编译器错误

{{1}}