这种尺寸安全的ZipWith变体需要哪些功能依赖,为什么?

时间:2012-02-16 06:58:46

标签: haskell types type-kinds

我正在尝试在具有类型参数化长度的列表上定义操作。我最终对这些列表有很多限制(MapFold,你有什么)所以我想使用新的GHC ConstraintKinds来简化我的生活。但是,我似乎无法弄清楚它们。

考虑以下(大大简化)的例子:

-- A list where length is implicit in the type.
-- This allows us to have classes like
-- Combineable a b c  u v w | ... where
--    combine :: (a -> b -> c) -> u -> v -> w
-- which is a version of ZipWith that only works on
-- lists of the same length.
data a :. b = !a :. !b

-- A simple class that works on our length-implicit lists
class Fold v a | v -> a where
  fold  :: (a -> a -> a) -> v -> a
instance Fold (a:.()) a where
  fold  f   (a:._) = a
instance Fold (a':.u) a => Fold (a:.a':.u) a where
  fold  f   (a:.v) = f a (fold f v)

-- A type constraint to simplify the constraints on our functions,
-- which in the real world also contain a bunch of things like
-- Map a a v v, Combineable a (Maybe a) (Maybe a) v w w, etc.
type NList v i = ( Fold (v i) i )

-- A function that uses our type constraint
foo :: (Num a, NList v a) -> v a -> a
foo = fold (+) 1

看起来对我很理智。对?错。

> foo ((1::Int) :. ())

Couldn't match type `Int' with `()'
When using functional dependencies to combine
  Fold (a :. ()) a,
    arising from the dependency `v -> a'
    in the instance declaration in `Data.Vec.Base'
  Fold (Int :. ()) (),
    arising from a use of `foo' at <interactive>:72:1-4
In the expression: foo ((1 :: Int) :. ())
In an equation for `it': it = foo ((1 :: Int) :. ())

对我来说,此错误消息大致翻译为“您为什么要尝试在类型级别进行编程?”

显然,我不太了解Constraint Kinds的含义,但我不确定我在哪里出错了。有人能发现错误吗?

1 个答案:

答案 0 :(得分:2)

我可能会误解你所追求的是什么,请原谅我,如果我完全不合适,但这就是我为使你的代码工作所做的。

v的种类
type NList v i = ( Fold (v i) i )

似乎与v

中的Fold类型相冲突
class Fold v a | v -> a where
    fold  :: (a -> a -> a) -> v -> a

如果我们只删除NList的定义并将foo更改为

,则代码适用于我
foo :: (Num a, Fold v a) => v -> a
foo = fold (+)

(我还为:.添加了一个固定声明以获得正确的关联性并添加了LANGUAGE pragma)

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FunctionalDependencies #-}

data a :. b = !a :. !b
infixr 5 :.

现在我们可以在GHCi中运行foo

*Main> foo (1:.())
1
*Main> foo (1:.2:.3:.())
6