Haskell:读取和输入签名

Gre*_*g S 6 haskell type-inference

read 在Prelude中被定义为

read :: (Read a) => String -> a
Run Code Online (Sandbox Code Playgroud)

并且可以用作例如read "1" :: Int.

现在是一个功能

readOne :: (Read a) => [String] -> (a, [String])
readOne (x:xs) = (read x,xs)
Run Code Online (Sandbox Code Playgroud)

readOne ["1","foo"]错误中的结果(如预期)一起使用

Ambiguous type variable 'a' in the constraint:
'Read a' arising from a use of 'readOne' at :1:0-18
Probable fix: add a type signature that fixes these type variable(s)

但是readOne ["1","foo"] :: Int不起作用

readOneInt :: [String] -> (Int, [String])
readOneInt = readOne
Run Code Online (Sandbox Code Playgroud)

工作得很好:

> readOneInt ["1", "foo"]
(1,["foo"])
Run Code Online (Sandbox Code Playgroud)

那么:如何在readOne不定义新功能的情况下添加类型签名readOneInt

sep*_*p2k 9

readOne ["1","foo"] :: Int不起作用,因为readOne无法返回一个Int,它总是返回一个元组,其第二个元素是一个[String].readOne ["1", "foo"] :: (Int, [String])将工作.

请注意,如果无法推断,则只需指定类型.如果readOne在需要的上下文中使用结果,则Int可以readOne不使用类型注释.例:

let inc (i, strs) = (i + 1, strs) in
inc (readOne ["1", "foo"])
-- (2, ["foo"])
Run Code Online (Sandbox Code Playgroud)

  • 谨防!最后的例子只适用于ghci,因为1的类型默认为"Integer".如果你问ghci表达式的类型(通过`:t`),你会得到`(Num a,Read a)=>(a,[String])`,它有与以前相同的问题.`asTypeOf`可以在这里提供帮助,如`asTypeOf(readOne ["1","foo"])(0 :: Double,[] :: [String])` - 我通常用反引号中的asTypeOf写的但是SO不喜欢双重逃脱的反叛. (2认同)