管理约束爆炸(Haskell)

时间:2015-01-25 23:40:25

标签: haskell constraints typeclass

我正在编写一个函数,我想在Vectors上使用它。换句话说,我有类似的东西:

import qualified Data.Vector.Generic as G
foo :: (G.Vector v a, G.Vector v b, G.Vector v c, G.Vector v d) 
    => v a -> v b -> v c -> v d 

这样用户可以选择使用Unboxed vs Storable矢量等。

但是如果我需要在v中放置中间值,我会得到Vector限制的组合爆炸,如:

foo :: (G.Vector v a, G.Vector v b, G.Vector v c, G.Vector v d,
        G.Vector v (a, b), G.Vector v (a, c), G.Vector v (c, b))
    => v a -> v b -> v c -> v d 

如何管理这种详细程度?有没有办法要么

1)GHC隐式生成约束

2)以某种方式将约束重构为一个公共类

1 个答案:

答案 0 :(得分:6)

类型系列可能很方便:

{-# LANGUAGE TypeFamilies, KindSignatures, DataKinds, TypeOperators, ConstraintKinds #-}

import qualified Data.Vector.Generic as G
import GHC.Prim

type family Vectors v (a :: [*]) :: Constraint where
  Vectors v '[]       = ()
  Vectors v (a ': as) = (G.Vector v a, Vectors v as)

这将创建一个类型级别函数,该函数获取类型列表并为具有这些类型的泛型Vector生成适当的约束。您可以像这样使用它:

foo :: (Vectors v [a, b, c, d, (a, b), (a, c), (c, b)]) => v a -> v b -> v c -> v d

这不是很理想,但确实会在一定程度上减少代码。

处理元组约束的急剧增加

由于具有更多类型级别技巧的对类型,您可以更好地处理这种约束的爆炸:

type family Combinations v (a :: [*]) :: Constraint where
  Combinations v '[]       = ()
  Combinations v (a ': as) = (G.Vector v a, CombComponent v a as, Combinations v as)

type family CombComponent v (a :: *) (bs :: [*]) :: Constraint where
  CombComponent v a '[]       = ()
  CombComponent v a (b ': bs) = (G.Vector v (a, b), G.Vector v (b, a), CombComponent v a bs)

它有点复杂,但现在我们可以像这样编写第二个foo签名:

foo :: (Combinations v [a, b, c, d]) => v a -> v b -> v c -> v d

这也可以进一步推广以允许签名如下:

foo :: (Combinations (G.Vector v) [a, b, c, d]) => v a -> v b -> v c -> v d