如何使用列表推导作为列表理解中的条件?

时间:2017-07-18 21:34:01

标签: string list haskell list-comprehension

我想只从字符串中获取大写字母,并且想知道字符串中的每个字母是否都包含在所有大写字母的列表中:

capsOnly = [ x| x<- string, (x elem ['A'..'Z'])]

问题是显然Haskell没有认识到逗号后面的部分应该是x的条件,并且给了我这个:

* Couldn't match expected type `(a0 -> t0 a0 -> Bool)
                                -> [Char] -> Bool'
              with actual type `Char'
* The function `x' is applied to two arguments,
  but its type `Char' has none
  In the expression: (x elem ['A' .. 'Z'])
  In a stmt of a list comprehension: (x elem ['A' .. 'Z'])

那么我该如何定义什么是Argument以及x来自哪个List? 或者那是不可能的?

我知道你也可以这样做:

onlyCaps = [ x| x<- string, x < 'a']

但我真的想知道我的第一种方法是否可行,以及如果它是

,如何写它

1 个答案:

答案 0 :(得分:6)

问题是不是列表理解本身。问题是x elem ['A'..'Z']没有多大意义。

elem :: Eq a => a -> [a] -> Bool是一个函数,它将元素和列表作为输入,并检查该元素是否属于列表。

所以你应该写它:

capsOnly = [ x | x <- string, elem x ['A'..'Z']]

或者使用backtics(使用 infix 表示法):

capsOnly = [ x | x <- string, x `elem` ['A'..'Z']]

然而 非常有效:它需要 O(n)来检查成员资格。由于我们检查范围,因此进行绑定检查更有效,例如:

capsOnly = [ x | x <- string, x >= 'A', x <= 'Z']

这需要在 O(1)中运行两次比较,使其更快。

我们在这里做的是过滤。通常使用filter :: (a -> Bool) -> [a] -> [a]作为谓词更好(更具描述性和声明性):

import Data.Char(isAsciiUpper)

capsOnly = filter isAsciiUpper string