2017-07-18 220 views
1

我想只从一个字符串的大写字母,并且有想法,看看是否在字符串中每个字母都包含在所有大写字母的列表:如何使用列表理解作为列表理解的条件?

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

问题是,显然哈斯克尔做不承认逗号后面的部分应该是关于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']) 

那么,如何界定什么是参数,什么是其中x来自列表? 或者这是不可能的?

我知道,你也可以不喜欢它:

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

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

回答

6

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

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

所以你应该把它写这样的:

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

或者选择使用backtics(使用符号):

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]这与isAsciiUpper :: Char -> Bool作谓语:

import Data.Char(isAsciiUpper) 

capsOnly = filter isAsciiUpper string 
+0

或'[X | x < - string,x \'elem \'['A'..'Z']]'(可能是OP试图写的第一个地方) – jwodder

+0

@jwodder:我想的完全一样:) –

+0

我们确定GHC不会将'elem x''''''Z']'优化为'x> ='A',x <='Z'' ..? – Redu