我正在编写一个函数来将String列表(从CSV文件中读取)转换为双打列表。它在第3行给出了一个错误。
stringToDouble :: [String] -> [Double]
stringToDouble [] = error "empty list"
stringToDouble [x] = read x :: Double -- the `read` gives me an error
stringToDouble (x:xs) = stringToDouble xs
是不是因为我没有将转换后的Double放入需要返回的列表中?
答案 0 :(得分:8)
错误源于read x
属于Double
类型,而不是[Double]
这一事实,但是,即使使用该修复程序,您的功能也无法正常工作。
让我们把你的函数放到单词中:“获取字符串列表的前面元素,将其作为双精度读取,然后对列表的其余部分执行相同操作”。现在让我们来看看你的功能:
stringToDouble :: [String] -> [Double]
stringToDouble [] = error "empty list"
stringToDouble [x] = read x :: Double -- Error
stringToDouble (x:xs) = stringToDouble xs
现在让我们将修复程序应用于它。此外,没有理由在空列表中出错;只是屈服和空双打名单:
stringToDouble :: [String] -> [Double]
stringToDouble [] = []
stringToDouble [x] = [read x :: Double] -- Put the single value into a list
stringToDouble (x:xs) = stringToDouble xs
问题在于递归步骤。在列表上调用stringToDouble
与在列表尾部调用stringToDouble
相同。第一个元素被简单地丢弃。您想转换头并将其放回列表中。
stringToDouble :: [String] -> [Double]
stringToDouble [] = []
stringToDouble [x] = [read x :: Double] -- Put the single value into a list
stringToDouble (x:xs) = (read x :: Double) : stringToDouble xs
其中(:)
是用于将元素附加到列表前面的运算符。由此,甚至不需要中间行,因为递归步骤将处理转换,空列表步骤将处理停止条件。
stringToDouble :: [String] -> [Double]
stringToDouble [] = []
stringToDouble (x:xs) = (read x :: Double) : stringToDouble xs
现在,实际上,你可能可能删除:: Double
部分,而Haskell会根据函数的类型约束找出你的意思,但它不会受到伤害,有时它会有助于将其留在其中。
答案 1 :(得分:1)
你是对的 - read x :: Double
是Double
类型,而函数的返回类型是[Double]
类型(意思是" {{1}列表1}}&#34)
这样的事情:
Double
应该有用。
请注意,如果您尝试单独转换列表中的每个元素,则应使用stringToDouble [x] = [read x :: Double]
编写函数,而不是使用显式递归。如果map
的类型为f
,则String -> Double
将是map f
类型的函数。