2017-09-20 19 views
2

Je dois vérifier si le dernier élément de la liste est en majuscules Par exemple "abc"-False, "abC"-TrueHaskell - consultez dernier élément de la liste

C'est ce que j'ai essayé

checkLast :: [a] -> Bool 
checkLast [] = False 
checkLast [x] = if isUpper x then True else False 
checkLast (x:xs) = if isUpper last then True else False 
+4

Quelques des choses.** 1 ** 'if isUpper x then True sinon False' est identique à' isUpper x'. ** 2 ** Jetez un second regard sur le cas final. D'où viens-tu? Pourquoi 'x: xs' est-il inutilisé? – SwiftsNamesake

Répondre

3

Think récursivement. checkLast (x:xs) est en train de vérifier checkLast xs:

checkLast :: [Char] -> Bool 
checkLast [] = False 
checkLast [x] = isUpper x 
checkLast (x:xs) = checkLast xs 

Notez que puisque vous utilisez isUpper pour vérifier les chaînes, il est plus logique que le type devrait être [Char], pas [a].

1

Une version fixe avec des commentaires:

import Data.Char (isUpper) 

checkLast :: [Char] -> Bool  -- it cannot be [a]: use of isUpper already limits possible type to [Char] 
checkLast [] = False 
checkLast [x] = isUpper x  -- the if .. can be shorter 
checkLast (x:xs) = checkLast xs -- drop first char and look at rest of string 
2

Vous pouvez utiliser récursion comme les autres réponses démontrent. Mais vous pouvez aussi utiliser des builtins pour construire une telle fonction.

Deux fonctions pertinentes ici sont null :: [a] -> Bool qui vérifie si une liste est vide, et last :: [a] -> a qui obtient le dernier élément.

Alors maintenant, nous pouvons construire une fonction:

import Data.Char(isUpper) 

checkLast :: [Char] -> Bool 
checkLast l = not (null l) && isUpper (last l) 

Nous voici donc affirmer que checkLast est True si la liste l n'est pas vide (not (null l)); et le dernier élément est un caractère majuscule isUpper (last l).

Cela sera probablement un peu plus rapide que les fonctions récursives, puisque nous ne testons le cas [] qu'une seule fois (dans null). last vérifie seulement deux cas: [x] et (x:xs) donc nous économisons sur [] contrôles.

Bien sûr, ces fonctions fonctionnent avec récursion, mais il est parfois utile de chercher des fonctions d'aide telles qu'une fonction est presque auto expliquer: ici les fonctions dit: "Une liste l est checkLast si elle est pas vide, et le dernier élément est une majuscule ".

+0

J'ai eu l'impression qu'il s'agissait d'une tâche, étant donné la question légèrement artificielle et la façon dont le PO l'a abordé. – SwiftsNamesake

+0

Je pense qu'il vaut mieux utiliser des fonctions totales que de protéger des fonctions partielles. – dfeuer

-2

Vous pouvez également procéder comme suit sans récursion

import Data.Char 

checkLast :: String -> Bool 
checkLast = (&&) <$> not . null <*> isUpper . head . reverse 

L'opérateur applicatif, <*> est un outil idéal pour alimenter un paramètre commun (la chaîne d'entrée ici) à deux fonctions différentes comme not . null et isUpper . head . reverse puis pour effectuer une opération (&&) sur leur résultat.

Selon le commentaire de @ dfeuer, je voudrais juste ajouter la solution suivante pour une meilleure performance. Vous n'avez pas besoin d'importer tout autre paquet que Data.Char

import Data.Char 

checkLast :: String -> Bool 
checkLast [] = False 
checkLast cs = isUpper $ foldr1 seq cs 
+1

Ceci, cependant, est une solution terrible. En plus d'être compliqué, il construit aussi une chaîne inversée uniquement pour regarder un élément et rejeter le reste. C'est terriblement inefficace. – dfeuer

+0

@dfeuer En quoi cet extrait de code est-il vraiment compliqué? C'est un modèle très basique chez Haskell. Selon l'inefficacité je crois que ce n'est pas inefficace dans la complexité du temps mais oui ... dans l'espace, on pourrait utiliser "last" à la place de "head". inverser ». – Redu

+1

L'utilisation de l'instance 'Applicative' pour les fonctions me semble plus obscurcissante que clarifier dans ce cas. – dfeuer

1

La façon la plus simple d'éviter la récursivité explicite, si vous souhaitez le faire, est probablement d'utiliser un pli:

lastMay :: [a] -> Maybe a 
lastMay = foldl' (\_ x -> Just x) Nothing 

checkLast = maybe True isUpper . lastMay 
+0

Ceci est également une solution terrible puisque vous devez importer le paquet 'Data.Maybe' juste pour implémenter cette tâche simple. Ce n'est absolument pas nécessaire. Voir ma réponse en annexe. – Redu

+0

@Redu, la seule fonction non-prélude que j'ai utilisée est 'foldl''. Mais les importations de base sont bénignes de toute façon. – dfeuer