[英]Illegal instance declaration for typeclass TF
I am having a problem declaring an instance of the following typeclass. 我在声明以下类型类的实例时遇到问题。 I tried to follow the advice in the error message from the ghci compiler but still cannot get the code to compile.
我试图遵循ghci编译器的错误消息中的建议,但仍然无法获取编译代码。 Any help would be appreciated.
任何帮助,将不胜感激。
class TF p where
valid :: p -> Bool
lequiv :: p -> p -> Bool
instance TF Bool
where
valid = id
lequiv f g = f == g
instance TF p => TF (Bool -> p)
where
valid f = valid (f True) && valid (f False)
lequiv f g = (f True) `lequiv` (g True)
&& (f False) `lequiv` (g False)
The error I am getting is: 我得到的错误是:
Illegal instance declaration for ‘TF (Bool -> p)’
(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 ‘TF (Bool -> p)’
The problem here is that you have a type constructor ( ->
) applied to things that aren't type variables. 这里的问题是你有一个类型构造函数(
->
)应用于非类型变量的东西。 There's a lot of ways you can deal with that: 有很多方法可以解决这个问题:
FlexibleInstances
. FlexibleInstances
。 This relaxes the assumption (made in the early days of Haskell, when it wasn't yet clear how difficult implementing type classes would be). Bool -> p
-- and in particular something that's polymorphic in the first argument will not match that shape. Bool -> p
- 以及特别是第一个参数中具有多态性的东西时,才会选择您的实例。不符合那个形状。 So valid id
will not typecheck without further annotations. valid id
将不会进行类型检查。 TypeFamilies
. TypeFamilies
。 This gives us (among other things) access to a constraint which demands that two particular types be equal. 这使我们(除其他外)访问要求两个特定类型相等的约束。 So with this extension, you could write
所以有了这个扩展,你可以写
instance (bool ~ Bool, TF p) => TF (bool -> p) where ...
Now this matches whenever the thing we're supplying has shape bool -> p
-- that is, any function at all -- and only after we have selected this instance does it check (in fact, enforce) that the argument type is Bool
. 现在,只要我们提供的东西形状
bool -> p
- 即任何函数 - 并且只有在我们选择了这个实例后才会检查(实际上是强制执行)参数类型是Bool
。 This means valid id
will typecheck; 这意味着
valid id
会出现问题; on the other hand, it also means you cannot declare instances for any other argument types. 另一方面,它还意味着您不能为任何其他参数类型声明实例。
Add a typeclass. 添加类型类。 In fact, the only thing you really care about is that you can list all the inhabitants of
Bool
in not too much time. 事实上,你唯一真正关心的是你可以在不太多的时间内列出
Bool
所有居民。 So you could instead declare a typeclass, say, Finite
, which you will instantiate at such types, and use it as the constraint on the argument type. 所以,你可以改为声明类型类,比如说
Finite
,你将在这些类型的实例,并用它作为参数的数据类型的约束。 Thus: 从而:
instance (Finite arg, TF p) => TF (arg -> p) where valid f = all (valid . f) universe lequiv fg = all (\\x -> fx `lequiv` gx) universe -- could also spell that lambda "liftA2 lequiv fg"
Then you would want to provide a Finite
instance for Bool
(which, luckily, is already available for you in the universe
package). 然后你想为
Bool
提供一个Finite
实例(幸运的是,在universe
包中已经可以使用了它)。 This is nice because it combines the strengths of the previous two approaches: this instance will be chosen as soon as we know the argument is a function, and you can declare instances for many argument types by adding Finite
instances for them. 这很好,因为它结合了前两种方法的优点:只要我们知道参数是一个函数,就会选择这个实例,并且可以通过为它们添加
Finite
实例来声明许多参数类型的实例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.