编译器不会选择多态常量值的类型类 [英] Compiler doesn't pick up typeclass for the polymorphic constant value

查看:49
本文介绍了编译器不会选择多态常量值的类型类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Haskell的新手,所以请原谅我.

I'm new to Haskell, so forgive me in advance.

为什么以下haskell代码无法编译?

Why doesn't the following haskell code compile?

似乎编译器以某种方式未能看到表达式(maxBound :: a)的类型是 a 且具有 Enum 提供的实例,而不是一些歧义类型变量'a0'.

It seems like the compiler somehow fails to see that the type of the expression (maxBound :: a) is a which has an Enum instance provided, not some type variable ‘a0’ which is ambiguous.

class (Enum a, Bounded a) => SafeEnum a where
  ssucc :: a -> a
  ssucc x = if (fromEnum x) < (fromEnum (maxBound :: a)) then succ x else minBound

  spred :: a -> a
  spred x = if (fromEnum x) > (fromEnum (minBound :: a)) then pred x else maxBound

Stepik.hs:3:32: error:
    • Could not deduce (Enum a0) arising from a use of ‘fromEnum’
      from the context: SafeEnum a
        bound by the class declaration for ‘SafeEnum’
        at Stepik.hs:(1,1)-(6,82)
      The type variable ‘a0’ is ambiguous
      These potential instances exist:
        instance Enum Ordering -- Defined in ‘GHC.Enum’
        instance Enum Integer -- Defined in ‘GHC.Enum’
        instance Enum () -- Defined in ‘GHC.Enum’
        ...plus six others

推荐答案

默认情况下,即使类型变量的范围从定义的类到类方法的类型签名(即 a SafeEnum a 类中的>与 ssucc :: a-> a a 中的 a 相同,它们不在范围内,从方法的类型签名到方法主体,因此在函数主体中的表达式 maxBound :: a ssucc spred a 与这些功能的类型签名中的 a 没有关系.

By default, even though type variables are scoped from the class being defined to the type signatures of the class's methods (i.e., the a in class SafeEnum a is the same a as the a in ssucc :: a -> a), they are not scoped from the type signatures of the methods to the method bodies, so in the expression maxBound :: a in the bodies of your functions ssucc and spred, the a has nothing to do with the a in the type signatures for those functions.

您可以启用 ScopedTypeVariables 扩展名,如下所示:

You can enable the ScopedTypeVariables extension, like so:

{-# LANGUAGE ScopedTypeVariables #-}

之后,类定义将键入check.

after which the class definition will type check.

请注意,如果您使用 forall 关键字,则此扩展名仅适用于常规"函数声明.因此,在类定义之外,您需要启用此扩展 并写:

Note that this extension only applies to "normal" function declarations if you use the forall keyword. So, outside of a class definition, you'd need to enable this extension and write:

ssucc :: forall a. a -> a 
ssucc x = ... maxBound :: a ...

或实际上:

ssucc :: forall a. (Enum a, Bounded a) => a -> a
ssucc x = ... maxBound :: a ...

,但是 class 子句中的规则不同.

but the rules are different inside a class clause.

请参见 GHC文档了解详情.

这篇关于编译器不会选择多态常量值的类型类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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