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.


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é .


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

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.


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

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)


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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.