我正在尝试在具有类型参数化长度的列表上定义操作。我最终对这些列表有很多限制(Map
,Fold
,你有什么)所以我想使用新的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的含义,但我不确定我在哪里出错了。有人能发现错误吗?
答案 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