Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.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 为什么read无法解析只有一个参数的类型?_Haskell_Typeclass - Fatal编程技术网

Haskell 为什么read无法解析只有一个参数的类型?

Haskell 为什么read无法解析只有一个参数的类型?,haskell,typeclass,Haskell,Typeclass,Haskell教程指出: 通过查看read的类型签名 read::read a=>String->a 因此,在运行时,GHCI无法知道我们想要返回哪种类型 ghci>阅读“4” 为什么需要提供第二个值,GHCI可以从中提取要比较的类型 将一个值和所有可能的Readtypeclass类型进行比较难道不可行吗 参考: 将单个值与所有可能的ReadTypeClass类型进行检查难道不可行吗 这样做会产生同样的结果读取“4”可能是可以从字符串中读取的任何内容,这就是ghci报告的内容: Prelu

Haskell教程指出:

  • 通过查看
    read的类型签名

    read::read a=>String->a

  • 因此,在运行时,GHCI无法知道我们想要返回哪种类型

    ghci>阅读“4”

为什么需要提供第二个值,GHCI可以从中提取要比较的类型

将一个值和所有可能的
Read
typeclass类型进行比较难道不可行吗

参考:

将单个值与所有可能的ReadTypeClass类型进行检查难道不可行吗

这样做会产生同样的结果<代码>读取“4”可能是可以从
字符串中读取的任何内容,这就是
ghci
报告的内容:

Prelude> :t read "4"
read "4" :: Read a => a
在实际执行解析之前,
reada=>a
表示潜在的解析结果。请记住,TypeClass是开放的,这意味着它可能是任何类型,具体取决于实例的存在

多个类型也完全可能共享相同的
Show
/
Read
文本表示,这就引出了我的下一点

如果您想检查字符串可以被解析为什么类型,那么至少需要解决可以接受给定输入的多个类型之间的歧义;这意味着您需要事先知道这些类型,
Read
无法做到这一点。即使你这样做了,你又如何提出这样的价值观呢?你需要把它打包成一些东西,这意味着你需要一个封闭的集合


总而言之,
read
签名在特定情况下尽可能精确。

并非作为答案,但这并不完全适合于评论

在ghci中,如果您只需执行一个
读取“5”
,那么ghci将需要一些帮助来确定您希望它是什么。但是,如果在某个地方使用了该结果,ghci(通常还有Haskell)可以找出类型。举个(愚蠢的)例子:

在这种情况下,不需要使用类型签名对读取进行注释,因为ghc可以从以下事实推断:
five
正在一个只接受Int的函数中使用。如果您添加了另一个具有不同签名的函数,该函数也尝试使用
five
,则最终会出现编译错误:

-- Adding this to our code above
-- Fails to compile
add1Integer :: Integer -> Integer
add1Integer i = i + 1

sixAsInteger = add1Integer five    
我认为你(在初学者中很常见——我自己也有过)对课程类型的误解。Haskell的工作方式在逻辑上与“对照Read typeclass的所有可能类型检查单个值”不兼容。实例选择基于类型。只有类型

您不应该将
read
看作是一个可以返回多种类型的神奇函数。它实际上是一个庞大的函数族,类型用于选择要使用的函数族成员。重要的是依赖的方向。类创建了一种情况,在这种情况下,值(通常是函数,但不总是)——运行时存在的东西——是根据类型选择的——编译时存在的东西

你会问“为什么不是另一个方向?为什么类型不能依赖于值?”,答案是Haskell不是这样工作的。它不是设计来的,它所基于的理论也不允许它。这有一个理论(依赖类型),GHC中添加了一些扩展,它们支持越来越多的功能集,这些功能在某些方面完成了依赖类型的工作,但目前还没有

即使是这样,这个例子仍然不能按照你想要的方式工作。依赖类型仍然需要知道某物是什么类型。你无法编写一个神奇的
read
的“返回任何东西”版本。相反,
read
的类型必须包含一些根据值计算类型的函数,并且本质上只适用于函数可以返回的封闭类型集


不过,最后两段有点像旁白。重要的一点是类是从类型到值的一种方式,通过方便的编译器支持,您可以在大多数情况下自动找到它。这就是他们设计要做的,也是他们能做的。这种设计的优点在于易于编译、行为的可预测性(开放世界假设)以及在编译时进行优化的能力。

您建议
阅读“5”
应该具有什么具体类型?说比那更糟不是那么简单。通常你不使用
读“5”
,因为你只需要写
5
readsomeunknownstring
应该有什么具体类型?错误读取/解析与成功的结果相同。例如,如果我需要一个数字,而用户发送了其他内容,那么我希望接收一个解析错误,而不是其他内容。类型签名根本不相似
show
的参数类型是多态的,这是很正常的。但是,
read
的结果类型是多态的,这意味着如果没有类型签名的明确指示,或者没有使用结果的其他函数的推断,编译器就无法理解您想要什么。您会说,“为什么需要提供第二个值?”。这个问题使我困惑。没有必要——事实上,在大多数设置中,甚至不允许——提供第二个值。例如,
read“4”3
将给您一个缺少实例的错误(在缺少某些非常非正统的附加代码的情况下)。你能举例说明你的意思吗,因为你在这里似乎没有使用标准术语?嗯,也许这很幼稚,但当
字符串的值为“4”时,
a
读取
签名中表示的所有潜在类型都受到约束。我想要的
-- Adding this to our code above
-- Fails to compile
add1Integer :: Integer -> Integer
add1Integer i = i + 1

sixAsInteger = add1Integer five