gpt4 book ai didi

Haskell Read(无实例)

转载 作者:行者123 更新时间:2023-12-04 16:24:38 25 4
gpt4 key购买 nike

我是Haskell初学者,有一个奇怪的问题。到目前为止,一切进展顺利,而且我已经能够正常使用Prelude读取功能。现在突然之间,我必须不断声明它的类型才能使用它。

为了使用它,我总是必须声明它或类似的东西。

let r = read::String-> Int

我曾尝试重新启动ghci,以为我不小心使读取重载,但无论何时只要我尝试正常使用它,
read "456"

我收到以下错误
No instance for (Read a0) arising from a use of `read'
The type variable `a0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance Read () -- Defined in `GHC.Read'
instance (Read a, Read b) => Read (a, b) -- Defined in `GHC.Read'
instance (Read a, Read b, Read c) => Read (a, b, c)
-- Defined in `GHC.Read'
...plus 25 others
In the expression: read "456"
In an equation for `it': it = read "456"

有谁知道这可能是什么原因以及如何解决?

最佳答案

首先,要解决您的问题,您可以使用以下几种方法之一指定您希望从read获得的结果:

首先,通过指定整个计算结果的类型:

read "456" :: Int

或通过指定函数的类型来读取:
(read :: String -> Int) "456"

为了解释为什么会发生这种情况,问题在于 read在其结果类型中是多态的。也就是说,定义了许多不同的 read函数,它们被定义为typeclass Read的一部分。该错误为您提供了原因说明:
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance Read () -- Defined in `GHC.Read'
instance (Read a, Read b) => Read (a, b) -- Defined in `GHC.Read'
instance (Read a, Read b, Read c) => Read (a, b, c)
-- Defined in `GHC.Read'
...plus 25 others
Read类型类为很多类型定义,它说错误中定义了28个实例。它是为Int,Integer,Double,String和不计其数的其他对象定义的。因此,为了使编译器知道要使用的typeclass实例,它需要能够从您指定的 read的类型中推断出来。如果给它 :: String -> Int,则编译器可以解决它。

为了理解它是如何工作的,让我们看一下 Read的类型类的一部分:
class Read a where
read :: String -> a

因此,对于给定的 a类型,必须定义 Read a实例,以便函数 read返回 a类型的值。因此,对于 Int,有一个 Read Int实例的定义,并且确实存在于 GHC-Read中。该实例定义了 read的工作方式。不幸的是,该实例相当钝,并且依赖于其他功能和其他类似的东西,但是为了完整起见,它是:
instance Read Int where
readPrec = readNumber convertInt
readListPrec = readListPrecDefault
readList = readListDefault

但是,要意识到的重要一点是,此实例意味着 read将适用于 Int。但是不久之后,就出现了一个实例:
instance Read Double where
readPrec = readNumber convertFrac
readListPrec = readListPrecDefault
readList = readListDefault

哦亲爱的。因此, read适用于 IntDouble!

Haskell语言可确保编译器通常会尝试为值推断唯一类型或失败。对于GHC中的语言有一些扩展,对此有一些奇怪的异常(exception),但是您在这里必须记住,Haskell试图阻止您用脚射击。如果您没有指定 read所期望的类型,则编译器可以推断任何类型,但这可能无效。您不希望您的代码突然开始以以前希望以 Double读取的浮点 Integer或任意精度的 Int读取,对吗?

在这种情况下,不指定类型只是导致编译器放弃,它不能确定地回答您提出的问题,即“我使用哪个 Read实例?” Haskell编译器不喜欢猜测。防止其猜测的一种方法是稍后使用明确的方式使用值,或定义明确使用 read的函数。例如,可以在您的代码中使用此函数,而不必键入 :: String -> Int:
readInt :: String -> Int
readInt = read

编译器可以确定在那里需要使用哪个 Read实例,如果需要,可以在代码中找出:
readInt "456"

编译器将知道 readInt的类型为 String -> Int,因此 readInt "456"的类型为 Int。就像Haskell一样,毫不含糊。

附录

GHCi中的语法在定义事物方面有些不同,因此,如果您仅使用GHCi与Haskell一起玩,我建议您切换到加载.hs文件并使用 :r命令重新加载它们。 GHCi的一个问题是,您必须使用“let”来定义所有内容,而当您开始编写程序时,这些内容会让您感到奇怪,而顶层定义则不需要这样做。另一个问题是 monomorphism restriction,坦率地说,它有点奇怪和古怪,因此不值得在此处详细介绍。

无论如何,尽管有两种方法(等效),但在GHCi中定义上面的 readInt的语法很简单。您已经知道一个,就是这样做的:
let readInt = read :: String -> Int

另一种方法是分别定义一个函数及其类型,这与在常规.hs文件中的实现方式类似:
let readInt :: String -> Int; readInt = read

惯用的Haskell都不是,但这是因为GHCi在编写代码时施加了古怪的限制,并且多行输入很奇怪。您可以这样做:
:{
let readInt :: String -> Int;
readInt = read
:}

这将使您接近惯用的Haskell定义。但是,如果将GHCi放在.hs文件中并使用 :load或将文件指定为 ghci ./somefile.hs,它将正确编译我的初始示例。

关于Haskell Read(无实例),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17710165/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com