声明一个类型类的列表实例

4
我正在通过UPENN Haskell讲义学习Haskell类型类,用示例代码创建自己的类型类:
class Listable a where
    toList :: a -> [Int]

instance Listable Int where
    toList x = [x]

instance Listable Bool where
    toList True  = [1]
    toList False = [0]

它适用于IntBool,但是当我添加一个[Int]的实例时,ghci会出现错误:

instance Listable [Int] where
    toList = id

错误:

‘Listable [Int]’的非法实例声明

(所有实例类型必须为(T a1 ... an)的形式,

其中a1 ... an是不同的类型变量,

每个类型变量在实例头中最多出现一次。

如果要禁用此功能,请使用FlexibleInstances。)

在‘Listable [Int]’的实例声明中

我尝试了几次但都失败了:

toList x = id x
toList x = x
toList = \x -> x

我该如何修复这个问题?

你有注意到错误信息中提到的 Use FlexibleInstances if you want to disable this 吗?纯 Haskell 在类型类方面相当严格;现代大多数程序都使用了多个扩展,因此编译器通常会建议你需要打开哪个扩展。 - chi
@chi 是的,我曾经这样做过,但我认为 ghci 希望我用 FlexibleInstances 替换关键字 instance,但事实证明这是错误的。 - Rahn
啊,我明白了 :) 扩展已经像下面的答案一样启用了。 - chi
你甚至可以更加通用化: instance Foldable t => Listable (t Int) where toList = Data.Foldable.toList - user2297560
1个回答

4
只需在您的源文件顶部添加以下行即可。
{-# LANGUAGE FlexibleInstances #-}

这将启用FlexibleInstances扩展,这是必需的,因为Haskell 98不允许这种形式的实例声明。
请注意,您也可以通过在调用ghcghci时添加-XFlexibleInstances标志来启用该扩展,但这被认为是一种不好的做法,因为它会为所有模块启用该扩展。这也意味着您的程序只能根据传递给编译器的命令行标志成功编译。这就是为什么最好按照上面所述的方式逐个模块启用扩展的原因。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接