我目前正在一个项目中工作,在那里我为一个类派生了一些实例。由于该类只有一个方法具有相同的定义,除了少数特定情况,我尝试定义一个可重叠的通用实例,然后定义我需要重叠的实例。
这不起作用,因为我收到重叠实例错误。做了一些测试,我们遇到了这个简化的例子,它几乎等同于我原来的问题:
{-# LANGUAGE FlexibleInstances, UndecidableInstances, MultiParamTypeClasses #-}
module Instance where
data Id a = Id a String
data C a = C a
class Bad a b where
bad :: a -> String
instance {-# OVERLAPPABLE #-} Bad a b where
bad = \_ -> "Default case"
instance {-# OVERLAPPING #-} Bad (Id a) (C a) where
bad = \_ -> "Id"
class Good a b where
good :: a -> String
instance {-# OVERLAPPABLE #-} Good a b where
good = \_ -> "Default case"
instance {-# OVERLAPPING #-} Good (Id a) b where
good = \_ -> "Id"
test = let a = Id () "a"
in putStrLn (good a) >> putStrLn (bad a)
(请注意,除非您评论第二个Bad实例,否则不会编译。)
Class Good没有任何问题(测试输出" Id")。如果我没有删除Bad的第二个实例,我会得到:
Overlapping instances for Bad (Id ()) b0
arising from a use of ‘bad’
Matching instances:
instance [overlappable] Bad a b -- Defined at Instance.hs:12:31
instance [overlapping] Bad (Id a) (C a)
-- Defined at Instance.hs:15:30
(The choice depends on the instantiation of ‘b0’
To pick the first instance above, use IncoherentInstances
when compiling the other instance declarations)
In the first argument of ‘putStrLn’, namely ‘(bad a)’
In the second argument of ‘(>>)’, namely ‘putStrLn (bad a)’
In the expression: putStrLn (good a) >> putStrLn (bad a)
我不明白为什么会发生这种情况,当它们之间的唯一区别是第二类参数中的附加限制时。
另外,不是重叠实例的重点是避免重叠错误吗?
此致
答案 0 :(得分:3)
根据我上面的评论,我认为您的pragma应该有with
prep ( from_qtr, from_yr, to_qtr, to_yr ) as (
select to_number(substr(:from_year, 2, 1)),
to_number(substr(:from_year, 4 )),
to_number(substr(:to_year , 2, 1)),
to_number(substr(:to_year , 4 ))
from dual
),
num ( rn ) as (select rownum from all_tab_columns)
select add_months( to_date(to_char(from_yr) || '/' || to_char(3 * from_qtr - 2)
|| '/01', 'yyyy/mm/dd') - 1,
3 * (rn - 1)
) as qtr_end_date
from prep cross join num
where rn <= 1 + 4 * (to_yr - from_yr) + (to_qtr - from_qtr)
order by qtr_end_date
;
而不是num ( rn ) as select 1 from dual union all select 2 from dual union all select 3 from dual ...... )
,
否则你会得到一个与函数签名中含糊不清的AllowAmbiguousTypes
不同的错误(至少我在GHC 8.0.1上做过)
UndecidableInstances
。
b
允许您为使用它们时不明确的函数编写签名。
相反,歧义检查被移动到呼叫站点。这与bad :: Bad a b => a -> String
之类的效果相当不错
指定那些不明确的变量。在这种情况下,AmbiguousTypes
总是不明确的,所以我们需要这个pragma移动到
呼叫站点上的错误消息。现在,我和你有同样的信息。
即使TypeApplications
和bad
Haskell抱怨的原因在于,取决于OVERLAPPABLE
如何实例化(也没有
指定),它将选择OVERLAPPING
的两个实例之一。换句话说,您可以希望b
与Bad
统一,
就像你做不到的那样,所以哈斯克尔举起双手说:“你还没有告诉我足够的b
让我成为
能够选择C a
&#34;。
另一方面,即使不知道b
,Haskell也知道Bad
和b
中的哪些实例更多
具体 - 它总是第二个(即使不知道Good a b
是什么情况)。
我真的建议您阅读有关overlapping instances的文档 因为它解释了整个算法。
您通常可以使用Good (Id a) b
(指定b
)或将类型类转换为类型系列来解决这些问题。