为数据类型列表创建实例 - Haskell

时间:2017-06-04 22:34:30

标签: list haskell instance typeclass

我觉得这应该很容易,但我已经坚持了很长一段时间。

haskell是否可以为某些数据类型的列表创建类型类的实例?

我想要实现的目标如下。

class Rename a where
    findSub :: a -> a

-- A 'normal' instance would look like this
instance Rename Atom where
    findSub ......

-- Now i want to acchieve something like this
instance Rename ([] Atom) where
    findSub ......

当我写这个时,我得到以下错误:

* Illegal instance declaration for `Rename [Atom]'
        (All instance types must be of the form (T a1 ... an)
         where a1 ... an are *distinct type variables*,
         and each type variable appears at most once in the instance head.
         Use FlexibleInstances if you want to disable this.)
    * In the instance declaration for `Rename ([] Atom)'
Failed, modules loaded: none.

我想知道如何解决这个问题以及为什么不允许这样做。

提前致谢。

1 个答案:

答案 0 :(得分:3)

它只需要语言扩展,因为Haskell 98标准在技术上不允许这种形式的实例。当错误消息显示启用扩展时,通常只需执行此操作[1]。 #include <iostream> using namespace std; int** add(int** first, int** second); int addAllElems(int** matrix); int addAllElems(int** matrix); void display(int** matrix); int main() { int first** = {{5,7,4}, {3,9,2}, {7,3,6}}; int second** = {{3,7,2}, {6,2,6}, {3,5,8}}; cout << "The first matrix is:" << endl; display(first); cout << endl; cout << "The second matrix is:" << endl; display(second); cout << endl; cout << "The sum of the two matrices is:" << endl; display(add(first, second)); cout << endl; cout << "The sum of all elements of the first matrix is: " << addAllElems(first) << endl; cout << endl; return 0; } int** add(int** first, int** second) { int[][] sum = new int[3][3]; for (int i = 0; i <= 2; i++) { for (int j = 0; j <= 2; j++) { sum[i][j] = first[i][j] + second[i][j]; } } return sum; } int addAllElems(int** matrix) { int sumOfElems = 0; for (int i = 0; i <= 2; i++) { for (int j = 0; j <= 2; j++) { sumOfElems += matrix[i][j]; } } return sumOfElems; } void display(int** matrix) { cout << "[" << endl; for (int i = 0; i <= 2; i++) { for (int j = 0; j <= 2; j++) { cout << matrix[i][j] << ", "; } cout << endl; } cout << "]" << endl; } 是一个非常普遍且被接受的扩展,所以只需添加

 In function 'int main()':
12:14: error: expected initializer before '*' token
63:1: error: expected '}' at end of input

位于文件顶部。

或者,通常可以定义这样的实例并递归地#34;在这种情况下,您不需要扩展,但除此之外,您可以免费获得更多实例,并且因为类型更多保证更一般。看看你是否可以定义

FlexibleInstances

相反,仅使用{-# LANGUAGE FlexibleInstances #-} instance (Rename a) => Rename [a] where findSub ... 而非具体为a的事实。当您可以通过这种方式定义实例时,这是一个很好的信号,表明您的设计是在正确的轨道上。

[1]有一些例外情况,例如RenameAtom,有时表明您对类型类分辨率的工作原理有错误的想法。