如何为类型家庭写gcast?

时间:2013-02-28 21:01:02

标签: haskell type-families

我正在尝试编写Data.Typeable.gcast的变体,它适用于类型* -> *的类型系列。我正在寻找的是:

{-# LANGUAGE TypeFamilies #-}
import Data.Typeable

type family T

gcastT :: (Typeable a,Typeable b) => T a -> Maybe (T b)
gcastT = undefined -- but that's not working too well!

类似于gcast :: (Typeable a,Typeable b) => f a -> Maybe (f b)

这可能吗?

可以将上下文更改为(Typeable (T a),Typeable (T b)) =>,但出于审美原因,我更喜欢此签名:gcast毕竟不需要Typeable1 f


一些背景,以防我正在解决我实际想要实现的问题:我的目标是编写一个函数matchAndExtract

matchAndExtract :: (Eq a, Typeable a, Eq b, Typeable b) => a -> b -> T b -> Maybe (T a)
matchAndExtract x k v = if (cast x == Just k) then gcastT v else Nothing

检查xk是否属于同一类型并且相等,然后返回提供的T b(我们知道它们与{{1}相同 - T可能不是单射的,但它一个函数!)或T a,否则。

我通过使用NothingT a包裹在newtype中,然后再次展开来解决问题:

gcast

但这只会让我错误的方式!这也适用于matchAndExtractF :: (Eq a, Typeable a, Eq b, Typeable b) => a -> b -> f b -> Maybe (f a) matchAndExtractF x k v = if (cast x == Just k) then gcast v else Nothing newtype WrapT a = WrapT { unWrapT :: T a } matchAndExtractViaWrap :: (Eq a, Typeable a, Eq b, Typeable b) => a -> b -> T b -> Maybe (T a) matchAndExtractViaWrap x k v = fmap unWrapT $ matchAndExtractF a k (WrapT v) 不是T a的实例的实例;在我看来,这似乎表明不应该需要Typeable上下文。

解决方案完全可以接受,但我想摆脱假的Typeable (T a)类型。

1 个答案:

答案 0 :(得分:4)

您尝试做的事情是不可能实现的。相反,你可以使用

type family T x :: *
newtype NT x = NT {fromNT :: T x}
gcastT :: (Typeable a, Typeable b) => NT a -> Maybe (NT b)
gcastT = gcast

在这种情况下,您不需要使用Eq约束。

另一种选择是将可键入的词典重新定义为GADT

data Type x where
  Typeable :: Typeable x => Type x

asT :: NT x -> Type x -> NT x
asT = const

gcastTD :: Type a -> Type b -> Type a -> Maybe (T b)
gcastTD t@Typeable Typeable x = fmap fromNT $ gcastT $ (NT x) `asT` t

(代码未经过测试,但应该几乎正确)

一旦你有了这个,你可以通过传递显式类型签名来使用它

type instance T Int = ()

justUnit = gcastTD (Typeable :: Type Int) (Typeable :: Type Int) ()