Pourquoi Prelude.read de Haskell ne renvoie-t-il pas un Peut-être?

108

Y a-t-il une bonne raison pour laquelle le type de Prelude.read est

read :: Read a => String -> a

plutôt que de renvoyer une Maybevaleur?

read :: Read a => String -> Maybe a

Puisque la chaîne pourrait ne pas être analysable Haskell, cette dernière ne serait-elle pas plus naturelle?

Ou même un Either String a, où Leftcontiendrait la chaîne d'origine si elle n'analysait pas, et Rightle résultat si c'était le cas?

Éditer:

Je n'essaye pas d'amener les autres à écrire un wrapper correspondant pour moi. Je cherche simplement à être assuré qu'il est sécuritaire de le faire.

Bilal Barakat
la source
14
Pourquoi n'en takeaccepte aucun Num a => a? Pourquoi y a-t-il un cas particulier de fmappour les listes? Pourquoi n'est-il Functorpas obligatoire pour les Monadinstances? Je m'attends à ce que la réponse soit similaire aux réponses à ces questions et aux questions connexes.
3
Eh bien, c'est pourquoi je l'ai formulé comme je l'ai fait, laissant la possibilité qu'il n'y ait aucune bonne raison. Bien que je soupçonne également qu'il n'y en a peut-être pas, comme pour les exemples bien connus que vous donnez, il vaut la peine de demander à être sûr que l'écriture de mon propre wrapper ne créera pas de problèmes imprévus en aval.
Bilal Barakat
J'espère qu'une readMaybefonction sera bientôt ajoutée.
augustss
Bons points @delnan, mais ne devrait pas l' takeêtre Integral n => n -> [a] -> [a]?
Doug McClean
@DougMcClean: Oui, ça devrait l'être Integral, pas Num- péter le cerveau.

Réponses:

106

Edit : À partir de GHC 7.6, readMaybeest disponible dans le Text.Readmodule du package de base, avec readEither: http://hackage.haskell.org/packages/archive/base/latest/doc/html/Text-Read.html#v: lirePeut-être


Excellente question! Le type de lecture lui-même ne changera pas de sitôt car cela casserait beaucoup de choses. Cependant, il devrait y avoir une maybeReadfonction.

Pourquoi n'y en a-t-il pas? La réponse est «l'inertie». Il y a eu une discussion en 2008 qui a été déraillée par une discussion sur «l'échec».

La bonne nouvelle est que les gens étaient suffisamment convaincus pour commencer à s'éloigner de l'échec dans les bibliothèques. La mauvaise nouvelle est que la proposition s'est perdue dans le shuffle. Il devrait y avoir une telle fonction, même si l'une est facile à écrire (et il existe des millions de versions très similaires flottant autour de nombreuses bases de code).

Voir également cette discussion .

Personnellement, j'utilise la version du package sécurisé .

sclv
la source
30

Ouais, ce serait pratique avec une fonction de lecture qui renvoie Maybe. Vous pouvez en fabriquer un vous-même:

readMaybe :: (Read a) => String -> Maybe a
readMaybe s = case reads s of
              [(x, "")] -> Just x
              _ -> Nothing
augustes
la source
3
Je vous remercie! J'espère que le montage ne semble pas ingrat! :) Je veux juste que ce soit clair que je ne demande pas par paresse ...
Bilal Barakat
6
Si @augustss ne peut pas le fournir, une meilleure réponse peut ne pas exister.
John L
2
Je ne pense pas qu'une version peut-être ait jamais été discutée dans la conception originale. Beaucoup de ces choses deviennent évidentes avec l'expérience, mais peuvent être difficiles à prévoir.
augustss
La raison pour laquelle reads renvoie une liste est pour le cas où il y a plusieurs analyses valides. Le cas Maybe est intermédiaire entre les lectures et les lectures.
Chris Kuklewicz
Je pense que cela nécessite une Read aclasse de caractères:readMaybe :: Read a => String -> Maybe a
David Tchepak
15

Outre l'inertie et / ou l'évolution des idées, une autre raison pourrait être qu'il est esthétiquement agréable d'avoir une fonction qui peut agir comme une sorte d'inverse de show. Autrement dit, vous voulez que ce read . showsoit l'identité (pour les types qui sont une instance de Showet Read) et qui show . readest l'identité sur la plage de show(c'est-à-direshow . read . show == show )

Avoir un Maybedans le type de readcasse la symétrie avec show :: a -> String.

yatima2975
la source
Merci d'avoir ajouté un nouvel angle! Ça a du sens. Mais pour y parvenir proprement, ne serait-il pas logique que show et read produisent un type distinct, par exemple "ParseableString"?
Bilal Barakat
1
@BilalBarakat: Le type distinct pourrait être newtype ValidShow a = ValidShow String. Le type fantôme le rend plus sûr de type.
yairchu
9
C'est un point intéressant, mais finalement, une fausse symétrie. Les programmeurs devraient privilégier la correction à l'esthétique.
Matt Fenwick
1
@yairchu Ce n'était pas immédiatement évident pour moi ce que vous vouliez dire à propos du type fantôme, alors je vais clarifier au cas où quelqu'un d'autre serait confus comme moi. Vous avez l'intention de quelque chose comme showThing :: Show a => a -> ValidShow aet readThing :: Read a => ValidShow a -> a, de sorte que le type de l'élément affiché soit mémorisé dans l'objet ValidShow. De cette façon, vous ne pouvez pas écrire readThing (showThing True) :: String.
amalloy du
12

Comme @augustss l'a souligné, vous pouvez créer votre propre fonction de lecture sécurisée. Cependant, sonreadMaybe n'est pas complètement cohérent avec read, car il n'ignore pas les espaces à la fin d'une chaîne. (J'ai fait cette erreur une fois, je ne me souviens pas très bien du contexte)

En regardant la définition de read dans le rapport Haskell 98 , nous pouvons la modifier pour implémenter un readMaybequi est parfaitement cohérent avec read, et ce n'est pas trop gênant car toutes les fonctions dont il dépend sont définies dans le Prelude:

readMaybe        :: (Read a) => String -> Maybe a
readMaybe s      =  case [x | (x,t) <- reads s, ("","") <- lex t] of
                         [x] -> Just x
                         _   -> Nothing
lpsmith
la source
1
Merci! +1 pour m'avoir alerté sur le problème des espaces blancs, qui n'avait pas été rendu explicite auparavant.
Bilal Barakat
3
Notez que si vous utilisez simplement le safepackage, vous obtenez une version correcte de readMaybeavailable (il s'appelle readMayet est identique à cette version.
Neil Mitchell
8

Cette fonction (appelée readMaybe) est maintenant dans le prélude Haskell! (À partir de la base actuelle - 4,6)

amindfv
la source
2
Eh bien, le texte lié dit qu'il est dans Text.Read et non dans Prelude (peut avoir changé), cependant, cela m'a toujours aidé!
Kapichu