我有一个类如下:
class Token a where
symbol :: a -> String
我还希望Token
的所有示例都有一个返回参数化类型的函数convert
。转换本身工作正常:
class Token a b where
convert :: a -> b
data Egal = One | Two
instance Token Egal Int where
convert One = 111
convert Two = 222
main = print $ show (convert One :: Int)
但是当我尝试同时使用symbol
和convert
时,我会得到关于二义性的错误。这是我的代码:
class Token a b where
convert :: a -> b
symbol :: a -> String
data Egal = One | Two
instance Token Egal Int where
convert One = 111
convert Two = 222
symbol One = "one"
symbol Two = "two"
main = print $ show (convert One :: Int)
我做错了什么?
编辑:阅读我自己的问题,我开始想知道:这是两个不同的类,我的data Egal
显示示例化两者吗?
2条答案
按热度按时间jdgnovmf1#
正如您在这里定义的那样,您可以拥有具有相同
a
但冲突b
s的示例。就像这样:那么,
symbol 'x'
应该是"x"
还是"xxxx"
?两者都是可能的,这取决于选择上述示例中的哪一个;对于symbol
应该使用哪个示例,因此应该得到哪个答案,这是不明确的。有多种方法可以解决这个问题。一种方法是简单地允许模糊性,并给予您自己指定在调用站点使用哪个示例的能力。您可以打开AllowAmbiguousTypes
和TypeApplications
扩展;然后:但在许多情况下,您确实希望编译器检查您是否创建了多个具有冲突
a
的示例。然后您可以使用FunctionalDependencies
扩展名:TypeFamilies
扩展名:在大多数情况下,它们或多或少具有相同的效果:冲突的示例被标记,并且不存在模糊性。
d7v8vwbk2#
在注解中,您写道类型
a
只能转换为单一类型b
。您当前的设计允许在同一个a
中使用多个b
。为什么GHC会抱怨?上面,
symbol
的两个定义都有A -> String
类型,所以GHC不能只从类型中选择使用哪个示例。一种(非理想的解决方案)是启用“模糊类型”Haskell扩展,并在每次调用
symbol
时手动选择示例。最好告诉Haskell类型
b
是由类型a
单独确定的,这样就不会有歧义。这可以使用函数依赖扩展来实现,但在我看来,最好使用类型族扩展来实现。