Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 为什么我必须在这里指定一个类型?_Haskell_Typeclass - Fatal编程技术网

Haskell 为什么我必须在这里指定一个类型?

Haskell 为什么我必须在这里指定一个类型?,haskell,typeclass,Haskell,Typeclass,我有以下代码: class to字符串a其中 toString::a->String 实例ToString字符串,其中 toString a=a 实例ToString Char,其中 toString a=[a] 实例ToString Int,其中 toString a=显示a 实例ToString整数,其中 toString a=显示a 实例ToString Float在哪里 toString a=显示a 实例ToString Double,其中 toString a=显示a 我可以做toS

我有以下代码:

class to字符串a其中
toString::a->String
实例ToString字符串,其中
toString a=a
实例ToString Char,其中
toString a=[a]
实例ToString Int,其中
toString a=显示a
实例ToString整数,其中
toString a=显示a
实例ToString Float在哪里
toString a=显示a
实例ToString Double,其中
toString a=显示a
我可以做
toString“Text”
toString't'
并且都可以很好地编译。但是如果我执行
到字符串5
的操作,我会得到一个错误。我被迫执行
toString(5::Int)

show
不需要指定类型即可工作。当我看到
Show
的实现时,我没有看到任何神奇之处:

实例显示Int,其中…

实例显示整数,其中…

我做错了什么,需要我指定类型,如何修复它

更新:


我按照下面的建议添加了
{-#LANGUAGE ExtendedDefaultRules}
,效果非常好。解决了我的问题。

您需要指定一个类型,因为
5
在Haskell中是多态的:

λ> :type 5
5 :: Num a => a
因此编译器不知道选择哪个
Num
实例。但是,由于以下原因,这在ghci中不起作用:

λ> toString 5
"5"

当您编写
到字符串“Text”或
到字符串“t”
时,Haskell能够准确地分辨出
“Text”
“t”
分别是:
[Char]
(又称
字符串
)和
Char
。因此,它可以选择一个实例并运行您的代码

与字符串5
有细微的不同。像
5
这样的数字文字在Haskell中重载,因此
5
可以是
Int
Double
,或者与没有
ToString
实例的
Num
实例完全不同的东西。因此没有指定我们应该使用哪个
ToString
实例(请注意,根据您选择的是
Int
还是
Double
,您将在现有实例中获得不同的可观察行为)。Haskell对这种情况的一般反应是报告一个模棱两可的类型错误,要求您做一些事情来更准确地确定类型

Haskell规范的作者认为这对于数字类型来说是一个非常常见和恼人的问题,因此他们为默认不明确的类型构建了一种机制,在某些条件下,这些条件被相当保守地设计为仅用于标准Haskell功能的数字文字。1

只有在以下两种情况下,类型才会默认:

  • 它的所有约束只涉及内置类型类
  • 至少有一个类是数值类(
    Num
    浮点
    等)
  • 所以
    show5
    之所以有效,是因为
    5
    类型的约束是
    (numa,showa)
    Num
    是一个数值类,所有约束都是内置类

    toString 5
    看起来应该基本相同,但是您得到了约束
    (Num a,toString a)
    ,并且由于
    toString
    不是内置类,因此默认设置不适用,这会给您留下一个不明确的类型错误

    GHCi中使用的扩展默认规则(或者如果您使用
    ExtendedDefaultRules
    扩展)放松了“仅内置类”规则(以及其他扩展),这使得
    (Num a,ToString a)
    毕竟符合默认条件

    GHC用户手册介绍了如何在GHCi中扩展常用的类型默认规则(或使用
    ExtendedDefaultRule
    s扩展),并将其与标准规则进行了比较:


    1在实践中,我发现这在实际开发中是一个极其罕见的问题(我通常使用警告类型默认的标志进行编译),但这是因为我采用了(常见的)做法,即为几乎所有顶级函数提供类型签名。当调用GHC来编译使用这种方法编写的整个模块时,几乎总是有足够的信息来指定所有类型,并且不需要使用默认值

    例如,
    toString x
    如果出现在
    x
    是一个类型为
    Int
    的参数的函数中,则它是完全正确的。如果
    x
    是一个没有显式类型的局部变量,那就更好了,但它也被传递给了一个需要
    Int
    参数的函数。或者与其他已知为
    Int
    的内容一起放入列表中。等等


    但是在GHCi中,您提供了一次一个地分析的表达式,并且通常不需要处理诸如类型签名之类的可选内容。在这些情况下,数字文本(和其他表达式)的类型模糊性更高,这是GHCi扩展默认规则的动机。

    具体而言,
    5
    表示
    来自整数(5::整数)
    ,因此
    到字符串5
    的类型模糊性与
    显示(阅读5)的原因相同
    是没有指定中间类型,因此编译器不知道在没有更多信息(例如类型签名)的情况下使用哪个实例。@behzad.nouri我在回答中谈到了为什么
    ExtendedDefaultRules
    在这里实际起到了作用。