我需要一些帮助来计算编译器错误,这真的让我疯狂......
我有以下类型类:
infixl 7 -->
class Selectable a s b where
type Res a s b :: *
(-->) :: (CNum n) => (Reference s a) -> (n,(a->b),(a->b->a)) -> Res a s b
我实例两次。第一次像魅力一样:
instance Selectable a s b where
type Res a s b = Reference s b
(-->) (Reference get set) (_,read,write) =
(Reference (\s ->
let (v,s') = get s
in (read v,s'))
(\s -> \x ->
let (v,s') = get s
v' = write v x
(_,s'') = set s' v'
in (x,s'')))
因为类型检查器推断
(-->) :: Reference s a -> (n,a->b,a->b->a) -> Reference s b
并且此签名与( - >)的类签名匹配,因为
Res a s b = Reference s b
现在我添加了第二个实例,一切都中断了:
instance (Recursive a, Rec a ~ reca) => Selectable a s (Method reca b c) where
type Res a s (Method reca b c) = b -> Reference s c
(-->) (Reference get set) (_,read,write) =
\(x :: b) ->
from_constant( Constant(\(s :: s)->
let (v,s') = get s :: (a,s)
m = read v
ry = m x :: Reference (reca) c
(y,v') = getter ry (cons v) :: (c,reca)
v'' = elim v'
(_,s'') = set s' v''
in (y,s''))) :: Reference s c
编译器抱怨
Couldn't match expected type `Res a s (Method reca b c)'
against inferred type `b -> Reference s c'
The lambda expression `\ (x :: b) -> ...' has one argument,
which does not match its type
In the expression:
\ (x :: b)
-> from_constant (Constant (\ (s :: s) -> let ... in ...)) ::
Reference s c
In the definition of `-->':
--> (Reference get set) (_, read, write)
= \ (x :: b)
-> from_constant (Constant (\ (s :: s) -> ...)) :: Reference s c
仔细阅读编译器告诉我它已经推断出( - >)的类型:
(-->) :: Reference s a -> (n,a->(Method reca b c),a->(Method reca b c)->a) -> (b -> Reference s c)
这是正确的,因为
Res a s (Method reca b c) = b -> Reference s c
但为什么它不能匹配这两个定义?
很抱歉没有提供更多的succint和独立的例子,但在这种情况下,我无法想象如何做到这一点......
答案 0 :(得分:4)
写作时
instance Selectable a s b where
您说任何类型组合都是可选择的实例。这为其他实例留下了空间。
当然,某些阴暗的编译器扩展将允许您编写更多(必然存在冲突)的实例,但您一定会遇到麻烦。
您是否可以使您的第一个实例更具体,以便它不再与您尝试编写的其他实例冲突?
遇到这样的问题通常表明类型类不是答案。如果你只编写两个实例,为什么不放弃重载并只编写两个特定的函数 - 每个用例一个?
答案 1 :(得分:0)
就像我在其他地方所说的那样,我不知道在第二个实例中发生的情况如此之少。但是,也许你可以通过这样做来使你的实例不重叠:
class Selectable a s b r where
(-->) :: (CNum n) => (Reference s a) -> (n,(a->b),(a->b->a)) -> r
instance Selectable a s b (Reference s b) where ...
instance (Recursive a, Rec a ~ reca) => Selectable a s (Method reca b c) (b -> Reference s c) where ...
这可能会导致您在呼叫站点出现问题,但使用两个名称不同的函数可能要好得多。