为什么read无法用一个参数解析类型?

时间:2019-01-24 10:33:10

标签: haskell typeclass

Haskell教程指出:

  • 通过查看read的类型签名

    read ::读取a =>字符串-> a

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

    ghci>读为“ 4”

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

针对Read类型类的所有可能类型检查单个值是否可行?

参考: http://learnyouahaskell.com/types-and-typeclasses

3 个答案:

答案 0 :(得分:3)

我认为您对类型类是一种误解(在初学者中比较普遍,我自己就有)。 Haskell的工作方式在逻辑上与“针对Read类型类的所有可能类型检查单个值”不兼容。实例选择基于类型。仅限类型。

您不应将read视为可以返回许多类型的神奇函数。实际上,它是一个庞大的功能家族,类型用于选择要使用的家族成员。重要的是依赖性的方向。类创建了一种情况,其中根据类型(在编译时存在的事物)选择值(通常是函数,但并非总是如此)-运行时存在的事物-选择类型。

您问的是“为什么不是另一个方向?为什么类型不能取决于值?”,答案是Haskell不能那样工作。它不是设计用来这样做的,它所基于的理论也不允许这样做。有一种关于(依赖类型)的理论,并且向GHC添加了扩展,以支持增加的功能集,这些功能可以执行依赖类型的某些方面,但是还不存在。

即使是这样,此示例仍然无法按照您想要的方式工作。依赖类型仍然需要知道什么是什么类型。您无法编写read的神奇“返回任何内容”版本。相反,read的类型必须包含一些根据值计算类型的函数,并且固有地仅适用于该函数可以返回的封闭类型集。

但是,最后两段有点放在一边。重要的是,类是从类型到值的转换方法,方便的编译器支持可在大多数时间自动为您解决。这就是他们旨在做的所有事情,而这是他们可以做的一切。从易于编译,行为的可预测性(开放世界假设)以及在编译时进行优化的能力等方面来看,该设计具有很多优势。

答案 1 :(得分:2)

  

相对于Read类型类的所有可能类型检查单个值是否可行?

这样做会产生相同的结果; read "4"可能是可以从String读取的任何内容,这就是ghci报告的内容:

Prelude> :t read "4"
read "4" :: Read a => a

直到您真正解析之前,Read a => a表示潜在解析结果。请记住,类型类是开放的,这意味着它可以是任何类型,具体取决于实例的存在。

完全有可能多个类型可以共享相同的Show / Read文本表示形式,这使我想到了下一点...

如果要检查可将字符串解析为哪种类型,则至少需要解决可以接受给定输入的多种类型之间的歧义;这意味着您需要事先知道Read做不到的那些类型。即使您这样做了,您又如何提出这样的价值呢?您需要将其打包成某种东西,这意味着您需要再次封闭集合。

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

答案 2 :(得分:2)

这并不是要回答,但这不能完全放在评论中。

在ghci中,如果您只是执行read "5",则ghci将需要一些帮助来确定您想要的内容。但是,如果在某个地方使用了该结果,ghci(通常是Haskell)可以 找出类型。对于(一个愚蠢的)示例:

add1 :: Int -> Int
add1 i = i + 1

five = read "5"

six = add1 five

在这种情况下,不需要使用类型签名来注释读取,因为ghc可以从five用于仅使用Int的函数中推断出它。如果您添加了另一个具有不同签名的函数,并且也尝试使用five,则会导致编译错误:

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

sixAsInteger = add1Integer five