定义了一个类型族(++);任何方式证明(vs ++ us)〜'[]暗示(vs~'[])和(us~'[])?

时间:2015-07-17 09:03:13

标签: haskell functional-dependencies type-families

定义:

type family (xs :: [*]) ++ (ys :: [*]) where
  '[] ++ ys = ys
  (x ': xs) ++ ys = x ': (xs ++ ys)

我有一个GADT,有点像

data Foo :: [*] -> * -> * where
  Foo0 :: a -> Foo '[] a
  Foo1 :: Foo '[a] a
  Foo2 :: Foo vs a -> Foo us a -> Foo (vs ++ us) a

我想做一些像

这样的事情
test :: Foo '[] Int -> Int
test (Foo0 x) = x
test (Foo2 x y) = test x + test y

但我无法在testx上使用y,因为必须证明x ~ Foo '[] Inty ~ Foo '[] Int。但我想说,vs ++ us ~ '[]意味着vsus的个人xy必然{{1} }}

有没有办法用类型系列做到这一点,或者可能切换到带有fundeps的多参数类型方法?

谢谢!

2 个答案:

答案 0 :(得分:6)

Don't touch the green smile!

  

“绿色粘液”的存在 - 返回类型中定义的函数   建设者 - 是一个危险的信号。

最简单的解决方法是概括test然后实例化:

gtest :: Foo xs Int -> Int
gtest (Foo0 x) = x
gtest (Foo2 x y) = gtest x + gtest y

test :: Foo '[] Int -> Int
test = gtest

答案 1 :(得分:4)

您可以添加两个类型系列作为++的反转,并且不失一般性,将它们作为约束添加到Foo2构造函数中。通过这些反向型家庭,GHC将能够准确地推断出您从中得到的内容。

以下是CutXCutY的示例实现,r ~ a ++ b< => a ~ CutY r b< => b ~ CutX r a

type family (xs :: [*]) ++ (ys :: [*]) where
  '[] ++ ys = ys
  (x ': xs) ++ ys = x ': (xs ++ ys)

type family CutX (rs :: [*]) (xs :: [*]) where
    CutX '[] xs = '[]
    CutX rs '[] = rs
    CutX (r ': rs) (x ': xs) = CutX rs xs

type family ZipWithConst (xs :: [*]) (ys :: [*]) where
    ZipWithConst '[] ys = '[]
    ZipWithConst xs '[] = '[]
    ZipWithConst (x ': xs) (y ': ys) = y ': ZipWithConst xs ys

type CutY rs ys = ZipWithConst rs (CutX rs ys)

data Foo :: [*] -> * -> * where
  Foo0 :: a -> Foo '[] a
  Foo1 :: Foo '[a] a
  Foo2 :: (rs ~ (vs ++ us), us ~ CutX rs vs, vs ~ CutY rs us) => Foo vs a -> Foo us a -> Foo rs a