Haskell教程指出:
通过查看read
的类型签名
read ::读取a =>字符串-> a
因此,GHCI无法知道我们在运行时要返回哪种类型
ghci>读为“ 4”
为什么有必要提供一个第二个值,GHCI可以从中提取一个要比较的类型?
针对Read
类型类的所有可能类型检查单个值是否可行?
答案 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