Retourner une valeur null dans Haskell sans constriction Polymorphisme
Que je suis "Real World Haskell", et vais dans le chapitre 2, où l'exercice est de créer un "lastButOne" fonction qui renvoie la seconde à la dernière valeur de la liste. Mon code d'origine était:
lastButOne xs = if null (tail (tail xs))
then head xs
else lastButOne (tail xs)
Qui fonctionne très bien, sauf si je lui donne une liste avec seulement 1 ou 2 éléments. Alors je l'ai modifié:
lastButOne xs = if null xs || null (tail xs)
then head xs
else
if null (tail (tail xs))
then head xs
else lastButOne (tail xs)
Qui vérifie si il a seulement 1 ou 2 des articles, mais ne parvient pas si il a seulement 1 point à cause de l'appel à tête. Mon problème est que je ne peux pas penser à quelque chose d'autre pour le retour autre que la "tête " xs", dans l'idéal, je veux qu'il à retourner la valeur null ou quelque chose comme ça, mais je ne peux pas trouver un "null" qui permet à la fonction de encore être polymorphe.
OriginalL'auteur Peter | 2011-11-10
Vous devez vous connecter pour publier un commentaire.
Peut-être vous êtes à la recherche d'un
Maybe
type:OriginalL'auteur
Il y a un certain nombre de réponses déjà postées sur la façon de faire ce travail, donc permettez-moi de répondre à la question plus fondamentale de "Pourquoi n'est-il pas 'null'?"
Cela fait partie de la philosophie de la type-checker en Haskell. la plupart des langues inclure une valeur spéciale qui signale une erreur ou un manque de données. Les exemples incluent
0
,-1
""
(la chaîne vide) JavaScriptsnull
ou Rubynil
. Le problème est que cela crée toute une classe de problèmes où la fonction d'appel ne traite qu'avec les "bonnes" valeurs et le programme se bloque ou pire corrompt les données lorsqu'un spécial valeur est retournée. Il y a aussi la question de la valeur spéciale étant conçu comme un régulier de valeur", c'est0
fait d'être un numéro et non pas un état d'échec.Dans votre problème, la question pourrait être encadré, "la fonction qui appelle
lastButOne
savoir quoi faire avecnull
?"Le problème de ne pas avoir une réponse valable pour certains sinon bien formé entrées est très fréquent en Haskell et a deux solutions typiques. La première est prise à partir d'Erlang: Fail rapidement et proprement. En vertu de cette solution, il est de la responsabilité de l'appelant pour s'assurer que les données sont "bonnes". Si ce n'est pas le programme meurt avec une erreur (ou l'exception est interceptée, mais c'est plus difficile en Haskell, puis d'autres langues) C'est la solution utilisée par la plupart des fonctions de liste par exemple
head
,tail
, etc...L'autre solution consiste à indiquer que la fonction peut ne pas produire de bonnes données. Le
Maybe a
type est le plus simple de ces solutions. Il vous permet de retourner une valeurNothing
qui fonctionne un peu comme lenull
vous êtes à la recherche pour. Mais il y a un coût à cela. Votre fonction du type de signature devientlastButOne :: [a] -> Maybe a
. Maintenant, à chaque appel de fonction doit prendre pas unea
mais unMaybe a
, et avant qu'il puisse obtenir sa réponse, il doit dire Haskell ce qu'il va faire si la réponse estNothing
.Maybe
utilisé un ensemble beaucoup plus que vous travaillez votre chemin à travers les CEP. Puis, quand vous revenez à Java ou autre, vous serez terrifié parce que de chaque variable dans votre programme pourrait être null si vous n'êtes pas prudent.OriginalL'auteur
Eh bien, cela dépend de combien de vérification des erreurs que vous voulez vraiment faire.
Je soupçonne que ce est seulement dans le Chapitre 2, vous êtes probablement censé ignorer ce cas limite. Haskell lui-même déclenche une exception:
L'alternative, si c'est un cas que vous aurez à traiter avec beaucoup, serait de changer le type de retour de
lastButOne
àMaybe a
et retourJust (head xs)
quand il fonctionne, etNothing
quand il échoue. Mais cela signifie que vous auriez toujours traiter avec le fait de vivre à l'intérieur de laMaybe
monade, qui peut ne pas être idéal (que vous auriez à "déballer" lesJust
valeur de l'utiliser).Maybe
.Oui, bien sûr, vous pouvez. Mais quand?
Je pense qu'il voulait dire par de bons vieux pattern matching:
case m of { Just x -> ... ; Nothing -> ... }
Avoir à déballer le Juste est précisément le point d'avoir Peut-être un type comme vous pouvez avoir le type de système vous protéger de NullPtrExceptions.Mais le point est que certaines de ces erreurs sont vraiment parfois préférable de laisser des erreurs. Il y a une raison pour laquelle le prélude n'a pas
head::[a]->Maybe a
.Je sais que beaucoup de Haskellers que préférez
head
et d'autres de son acabit pour retourner unMaybe
valeur.OriginalL'auteur
Pourquoi n'utilisez-vous pas la correspondance de modèle pour gérer le cas où vous avez seulement 1 ou 2 éléments?
Quelque chose comme:
null
n'est pas le traditionnel "null" la valeur de sa fonction pour tester si une liste est vide. Je ne pense pas que ce code compile...Je sais, c'est pourquoi j'ai édité. @missingno
OriginalL'auteur
Un exemple de gestion d'erreur étendu" mentionné par @Andrew Jaffe pourrait être:
Dans ce cas, il est possible de retourner
Either
type:Right x
en cas de succès etLeft "Error in lastButOne"
en cas d'échec, mais de nombreux autres exemples deMonadError String m
sont possibles.Également lire 8 façons de signaler les erreurs en Haskell pour plus de possibilités.
OriginalL'auteur