我正在尝试在类型级别构建一个列表,但是在弄清楚如何强制执行约束时遇到了一些麻烦。
我的基本代码是:
data Foo z q = Foo1 (z q)
| Foo2 (z q)
class Qux q -- where ...
class Baz z -- where ...
class Bar a where -- a has kind *->*
type BCtx a q :: Constraint -- using ConstraintKinds to allow constraints on the concrete type
f :: (BCtx a q) => a q -> a q -> a q
g :: (BCtx a q, BCtx a q') => a q -> a q'
instance (Baz z) => Bar (Foo z) where
type BCtx (Foo z) q = (Num (z q), Qux q) -- for example
f (Foo1 x) (Foo1 y) = Foo1 $ x+y -- these functions need access to the type q to do arithmetic mod q
f (Foo1 x) (Foo2 y) = Foo2 $ x-y
-- ...
您可以认为q
上面的 s 代表主要权力。我还想使用qi
s 的类型列表来表示合数。我在想像:
data QList qi qs = QCons qi qs
| QNil
与数据
data FList c q = FNil
| FCons (c (Head q)) (FList c (Tail q))
where(Head q)
应该对应qi
和(Tail q)
应该对应qs
。请注意,q
参数 forFList
不是(必然) a (Qux q)
,它是的列表。(Qux qi)
(我不想详细说明这个列表,因为这是我提出的设计问题之一)。我想在以下方面“按模数”工作FList
:
instance (Bar c) => Bar (FList c) where
type BCtx (FList c) q = () -- Anything I put here is not enough
f (FCons x xs) (FCons y ys) = FCons (f x y) (f xs ys)
-- the left call to `f` calls a concrete instance, the right call to `f` is a recursive call on the rest of the list
-- ...
在 GHC 中将这些代码片段一起编译会导致(模转录、抽象和输入错误):
Could not deduce (BCtx c (Head q), BCtx c (Tail q))
接着
Could not deduce (BCtx c (Head (Tail q)), BCtx c (Tail (Tail q)))
等等
我明白为什么会收到此错误,但不知道如何解决。
具体来说,我期待一个FList c q
类型 wherec~Foo z
和q~QCons q1 (QCons q2 QNil)
,当然我的列表将满足每个级别的所有 BCtx 约束。
我不确定修复这些特定错误是否会导致编译代码,但这是一个开始。整个 Bar 类基本是固定的(必须有 Constraint kind,Bar 的实例必须有 kind * -> *)。我不相信我可以使用存在类型来创建通用对象列表,因为我需要访问qi
参数。我愿意更改类型FList
并QList
允许我在 Bars 集合上按模数工作。
谢谢你的时间!