列表列表上的模式匹配

时间:2013-11-03 15:24:51

标签: haskell

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

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

2 个答案:

答案 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 xsx的类型为String,而onlyCapitals xs的类型为[String]++运算符要求它的两个操作数具有相同的类型,并假定它们是列表。左操作数是[Char],然后它也期望右操作数为[Char]。由于右操作数实际上是[String][[Char]],因此报告:“无法将类型[Char][[Char]]匹配”,简化为“不能”匹配类型Char[Char]“,因为”外部“列表可以匹配。

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

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