0

如果不是,我想制作字符串的第一个字符。这就是我正在做的事情:

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
4

2 回答 2

4

首先要意识到

(++) :: [a] -> [a] -> [a]
(:)  :: a -> [a] -> [a]

所以你的第一个错误是你试图做类似String ++ [String]类型错误的事情,而不是你想要(:)

下一个问题是

toUpper (head x) : tail x ++ onlyCapitals xs

问题是 和 的关联性和优先级++:在右边。所以这被解析为

toUpper (head x) : (tail x ++ onlyCapitals xs)

这已通过显式括号修复并再次切换++:

(toUpper (head x) : tail x) : onlyCapitals xs

风格注释

现在这有效,除非你传递一个空字符串,在这种情况下它会崩溃。相反,也许这样的事情会更好

onlyCapitals :: [String] -> [String]
onlyCapitals = map cap
  where cap "" = ""
        cap (x : xs) = toUpper x : xs

我们抽象出列表的显式递归和构造,并将其留给map. 然后我们正确处理""和大写非空字符串的第一个字符。

于 2013-11-03T15:40:00.467 回答
1

让我们采取您标记的线-- 1: then x ++ onlyCapitals xs。的类型xString,而 的类型onlyCapitals xs[String]。运算符要求它的++两个操作数属于同一类型,并且假定它们是列表。左操作数是 a [Char],然后它期望右操作数[Char]也是。由于正确的操作数实际上[String][[Char]],因此它报告:“无法将类型[Char][[Char]]”匹配,简化为“无法将类型Char[Char]”匹配,因为可以匹配“外部”列表。

所以你不想在++那里使用运算符,而是使用:运算符。其他错误源于标记行上的类似问题,-- 2 and 3解决方案是非常仔细地检查您的子表达式具有哪些类型以及应用运算符的顺序。

关于此方法的一个注意事项:您实际上并不需要条件。toUpper 在已经是资本的东西上工作得很好,所以“else”可以应用于列表的每个成员。

于 2013-11-03T15:38:03.923 回答