如果不是,我想制作字符串的第一个字符。这就是我正在做的事情:
import Data.Char
onlyCapitals :: [String] -> [String]
onlyCapitals [] = []
onlyCapitals (x:xs) = if isUpper $ head x
then x ++ onlyCapitals xs -- 1
else toUpper (head x) : tail x ++ onlyCapitals xs -- 2 and 3
main = print $ onlyCapitals ["Aaaa", "bbb", "ffff"]
我有3个错误:
Couldn't match type `Char' with `[Char]'
Expected type: [String]
Actual type: String
Couldn't match type `Char' with `[Char]'
Expected type: String
Actual type: Char
Couldn't match type `Char' with `[Char]'
Expected type: [String]
Actual type: String
答案 0 :(得分:4)
要实现的第一件事
(++) :: [a] -> [a] -> [a]
(:) :: a -> [a] -> [a]
所以你的第一个错误就是你试图做String ++ [String]
这样的类型错误,而不是(:)
下一个问题是
toUpper (head x) : tail x ++ onlyCapitals xs
问题是++
和:
的关联性和优先级都与右侧的级别相同。所以这被解析为
toUpper (head x) : (tail x ++ onlyCapitals xs)
这是通过明确的parens修复并再次将++
切换为:
(toUpper (head x) : tail x) : onlyCapitals xs
现在这个工作,除非你传递一个空字符串,在这种情况下它会崩溃。相反,也许这样的事情会更好
onlyCapitals :: [String] -> [String]
onlyCapitals = map cap
where cap "" = ""
cap (x : xs) = toUpper x : xs
我们抽象出列表的显式递归和构造,并将其留给map
。然后我们正确处理""
并将非空字符串的第一个字符大写。
答案 1 :(得分:1)
我们选择您标记为-- 1
的行:then x ++ onlyCapitals xs
。 x
的类型为String
,而onlyCapitals xs
的类型为[String]
。 ++
运算符要求它的两个操作数具有相同的类型,并假定它们是列表。左操作数是[Char]
,然后它也期望右操作数为[Char]
。由于右操作数实际上是[String]
,[[Char]]
,因此报告:“无法将类型[Char]
与[[Char]]
匹配”,简化为“不能”匹配类型Char
与[Char]
“,因为”外部“列表可以匹配。
因此,您不希望在那里使用++
运算符,而是使用:
运算符。其他错误源于标记为-- 2 and 3
的行上的类似问题,解决方案是非常仔细地检查子表达式的类型以及运算符的应用顺序。
关于此方法的一点注意事项:您实际上并不需要条件。 toOpper在已经是资本的东西上工作得很好,所以'else'可以只应用于列表的每个成员。