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

Hob*_*mok 1 string haskell list-comprehension list

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

capsOnly = [ x| x<- string, (x elem ['A'..'Z'])]
Run Code Online (Sandbox Code Playgroud)

问题是显然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'])
Run Code Online (Sandbox Code Playgroud)

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

我知道你也可以这样做:

onlyCaps = [ x| x<- string, x < 'a']
Run Code Online (Sandbox Code Playgroud)

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

Wil*_*sem 6

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

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

所以你应该写它:

capsOnly = [ x | x <- string, elem x ['A'..'Z']]
Run Code Online (Sandbox Code Playgroud)

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

capsOnly = [ x | x <- string, x `elem` ['A'..'Z']]
Run Code Online (Sandbox Code Playgroud)

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

capsOnly = [ x | x <- string, x >= 'A', x <= 'Z']
Run Code Online (Sandbox Code Playgroud)

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

我们在这里做的是过滤.通常它是更好(更多的描述和声明)使用filter :: (a -> Bool) -> [a] -> [a]与此isAsciiUpper :: Char -> Bool作谓语:

import Data.Char(isAsciiUpper)

capsOnly = filter isAsciiUpper string
Run Code Online (Sandbox Code Playgroud)