类型TF的非法实例声明 [英] Illegal instance declaration for typeclass TF

查看:94
本文介绍了类型TF的非法实例声明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个问题,声明下面的typeclass的一个实例。我试图按照来自ghci编译器的错误消息中的建议,但仍无法获得编译的代码。任何帮助将不胜感激。

  class TF p where 
valid :: p - > Bool
lequiv :: p - > p - > Bool

实例TF Bool
其中
valid = id
lequiv f g = f == g

实例TF p => TF(Bool - > p)
其中
有效f =有效(f真)&&有效(f False)
lequiv f g =(f True)`lequiv`(g True)
&& (f False)`lequiv`(g False)

我得到的错误是:

 'TF(Bool  - > p)'
的非法实例声明(所有的实例类型都必须是T a1 ... an)
其中a1 ... an是*不同类型变量*,
,每个类型变量在实例头中至多出现一次
如果您想要使用FlexibleInstances )
在'TF(Bool - > p)'的实例声明中'


- > )应用于非类型变量的东西。有很多方法可以解决这个问题:


  1. FlexibleInstances 。这放松了这个假设(在Haskell早期阶段,当时还不清楚实现类型类会有多困难)。这根本没有争议。另一方面,类型推理并不能很好地发挥它的作用:只有当我们知道我们正在提供某种形状的东西时,才会选择您的实例 Bool - > ; p - 特别是第一个参数中的多态的东西不符合该形状。因此,有效id 不会在没有进一步注释的情况下进行类型检查。 >。这使我们(除其他事项外)能够获得要求两种特定类型相等的约束。因此,通过这个扩展,你可以写出

      instance(bool〜Bool,TF p)=> TF(bool  - > p)其中... 

    供应已经形成 bool - > p - 也就是任何函数 - 只有在我们选择了这个实例之后,才会检查(实际上是强制执行)参数类型是 Bool 。这意味着有效的id 将会检测到;另一方面,这也意味着你不能为任何其他参数类型声明实例。

  2. 添加一个类型类型。事实上,你唯一真正关心的是你可以在不多的时间内列出 Bool 的所有居民。所以你可以改为声明一个类型类,比如 Finite ,您将在这些类型中实例化,并使用 it 作为参数类型的约束。因此:

      instance(Finite arg,TF p)=> TF(arg  - > p)其中
    有效f =全部(有效.f)宇宙
    lequiv fg =全部(\ x - > fx`lequiv` gx)宇宙
    - - 也可以拼写那个lambdaliftA2 lequiv fg

    然后你想提供一个 > Bool (这很幸运,已经可以在 universe中找到) $ c>包)。这很好,因为它结合了前两种方法的优点:只要我们知道参数是一个函数,就会选择这个实例,并且可以通过添加 Finite 来为许多参数类型声明实例。 code>实例。



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. 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:

  1. 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). This is not very controversial at all. On the other hand, it doesn't play that well with type inference: your instance will only be chosen when we know that we're supplying something of the shape Bool -> p -- and in particular something that's polymorphic in the first argument will not match that shape. So valid id will not typecheck without further annotations.
  2. 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. This means valid id will typecheck; on the other hand, it also means you cannot declare instances for any other argument types.

  3. 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. 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. Thus:

    instance (Finite arg, TF p) => TF (arg -> p) where
        valid f = all (valid . f) universe
        lequiv f g = all (\x -> f x `lequiv` g x) universe
        -- could also spell that lambda "liftA2 lequiv f g"
    

    Then you would want to provide a Finite instance for Bool (which, luckily, is already available for you in the universe package). 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.

这篇关于类型TF的非法实例声明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆