2017-07-18 1 views
1

Je veux obtenir seulement les lettres majuscules d'une chaîne, et a eu l'idée de voir si chaque lettre dans la chaîne est contenue dans une liste de toutes les lettres majuscules:Comment utiliser la compréhension de liste comme condition dans une compréhension de liste?

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

le problème est que, apparemment, Haskell ne ne reconnaît pas que la partie derrière la virgule est censé être une condition pour x, et me donne ceci:

* 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']) 

Alors, comment puis-je définir ce qui est de l'argument et quelle est la liste où x vient? Ou est-ce impossible?

Je sais que vous pouvez aussi le faire comme:

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

mais je veux vraiment savoir si ma première approche est possible, et comment l'écrire si elle est

Répondre

6

Le problème est pas avec la compréhension de la liste lui-même. Le problème est que x elem ['A'..'Z'] n'a pas beaucoup de sens.

elem :: Eq a => a -> [a] -> Bool est une fonction qui prend en entrée un élément et une liste et vérifie si l'élément appartient à la liste.

Vous devriez écrire comme:

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

Ou bien utiliser backtics (pour utiliser infix notation):

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

Ceci est cependant pas très efficace: il faut O (n) pour vérifier l'adhésion. Depuis, nous vérifions une gamme, il est plus efficace de faire des contrôles liés, comme:

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

Cela nécessite deux comparaisons qui fonctionnent dans O (1) rendant plus rapide.

Ce que nous faisons ici est le filtrage. En général, il vaut mieux (plus descriptif et déclarative) à utiliser pour cette filter :: (a -> Bool) -> [a] -> [a] avec isAsciiUpper :: Char -> Bool comme prédicat:

import Data.Char(isAsciiUpper) 

capsOnly = filter isAsciiUpper string 
+0

Ou '[x | x <- chaîne, x \ 'elem \' ['A' .. 'Z']] '(probablement ce que l'OP essayait d'écrire en premier lieu) – jwodder

+0

@jwodder: Je pensais exactement la même chose :) –

+0

Sommes-nous sûrs que GHC n'optimiserait pas 'elem x ['A' .. 'Z']' à 'x> = 'A', x <= 'Z'' ..? – Redu