我正在通过learnyouahaskell章节工作,并一直在试验递归函数(和守卫)。我找到了一些练习,其中一个练习是从[Int]形式的String中检索十进制数。这就是我到目前为止所做的:
retrieveDecimalsFromString :: String -> [Int]
retrieveDecimalsFromString (x:xs)
| x `elem` ['0'..'9'] = x:retrieveDecimalsFromString xs
| otherwise = retrieveDecimalsFromString xs
这种崩溃,我理解,因为我返回的是String而不是[Int]。我似乎无法找到解决方案。也许我的方法是错的。或者(没有递归)我试过:
retrieveDecimalsFromString :: String -> [Int]
retrieveDecimalsFromString xs = filter (`elem` ['0'..'9']) xs
导致同样的问题。以上可以做到吗?
答案 0 :(得分:4)
使用递归时,应该具有基本条件。在你的代码中,当字符串为空时,它会做什么?这是你的基本条件。所以,像这样改变功能定义
retrieveDecimalsFromString :: String -> [Int]
retrieveDecimalsFromString "" = []
基本条件表示,如果输入为空字符串,我将返回一个空列表。
现在,当x
是其中一个数字时,x:retrieveDecimalsFromString xs
会做什么?它会尝试创建一个列表。但第一个元素x
是Char
,根据retrieveDecimalsFromString
的定义,返回值为[Int]
。因此,您需要将Char
转换为Int
,就像这样
retrieveDecimalsFromString (x:xs)
| x `elem` ['0'..'9'] = (digitToInt x):retrieveDecimalsFromString xs
| otherwise = retrieveDecimalsFromString xs
在filter
版本中,您说retrieveDecimalsFromString
将根据签名返回[Int]
,但过滤结果为[Char]
。这就是为什么它不起作用。您可以通过更改这样的任何一个地方的类型来解决这个问题
retrieveDecimalsFromString :: String -> [Char]
retrieveDecimalsFromString xs = filter (`elem` ['0'..'9']) xs
或者
retrieveDecimalsFromString :: String -> [Int]
retrieveDecimalsFromString xs = map digitToInt $ filter (`elem` ['0'..'9']) xs
注意: digitToInt
功能位于Data.Char
。所以你需要在使用之前导入它。