¿Por qué Haskell's Prelude.read no devuelve Quizás?

108

¿Existe una buena razón por la que el tipo de Prelude.read sea

read :: Read a => String -> a

en lugar de devolver un Maybevalor?

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

Dado que la cadena podría no ser analizable Haskell, ¿no sería esto último más natural?

O incluso Either String a, ¿dónde Leftcontendría la cadena original si no se analizara y Rightel resultado si lo hiciera?

Editar:

No estoy tratando de que otros me escriban una envoltura correspondiente. Solo busco la tranquilidad de que es seguro hacerlo.

Bilal Barakat
fuente
14
¿Por qué no takeacepta ninguno Num a => a? ¿Por qué hay un caso especial de fmaplistas de for? ¿Por qué Functorno es obligatorio para las Monadinstancias? Espero que la respuesta sea similar a las respuestas a estas y otras preguntas relacionadas.
3
Bueno, es por eso que lo expresé como lo hice, dejando abierta la opción de que no hay una buena razón. Si bien también sospecho que podría no haberlo, como en los ejemplos conocidos que da, vale la pena preguntar para asegurarse de que escribir mi propio contenedor no creará problemas imprevistos en el futuro.
Bilal Barakat
Espero readMaybeque pronto se agregue una función.
2011
Buenos puntos @delnan, ¿pero no debería takeser así Integral n => n -> [a] -> [a]?
Doug McClean
@DougMcClean: Sí, en realidad debería ser Integral, no Num: un pedo cerebral.

Respuestas:

106

Editar : A partir de GHC 7.6, readMaybeestá disponible en el Text.Readmódulo en el paquete base, junto con readEither: http://hackage.haskell.org/packages/archive/base/latest/doc/html/Text-Read.html#v: readMaybe


¡Gran pregunta! El tipo de lectura en sí no cambiará pronto porque eso rompería muchas cosas. Sin embargo, debería haber una maybeReadfunción.

¿Por qué no está ahí? La respuesta es "inercia". Hubo una discusión en el '08 que se descarriló por una discusión sobre "fallar".

La buena noticia es que la gente estaba lo suficientemente convencida como para empezar a alejarse del fracaso en las bibliotecas. La mala noticia es que la propuesta se perdió en la confusión. No debería ser una función de este tipo, aunque uno es fácil escribir (y hay infinidad de versiones muy similares que flotan alrededor de muchas bases de código).

Vea también esta discusión .

Personalmente, utilizo la versión del paquete seguro .

sclv
fuente
30

Sí, sería útil con una función de lectura que devuelva Quizás. Puedes hacer uno tú mismo:

readMaybe :: (Read a) => String -> Maybe a
readMaybe s = case reads s of
              [(x, "")] -> Just x
              _ -> Nothing
augusts
fuente
3
¡Gracias! ¡Espero que la edición no suene ingrata! :) Solo quiero dejar en claro que no pregunto por pereza ...
Bilal Barakat
6
Si @augustss no puede proporcionarlo, es posible que no exista una mejor respuesta.
John L
2
No creo que nunca se haya discutido una versión tal vez en el diseño original. Muchas de estas cosas se vuelven obvias con la experiencia, pero pueden ser difíciles de predecir.
agosto de 2011
La razón por la que lee devuelve una lista es para el caso en el que hay varios análisis válidos. El caso Maybe es intermedio entre lecturas y lecturas.
Chris Kuklewicz
Creo que esto requiere una Read aclase de tipo:readMaybe :: Read a => String -> Maybe a
David Tchepak
15

Aparte de la inercia y / o los cambios de percepción, otra razón podría ser que es estéticamente agradable tener una función que pueda actuar como una especie de inverso de show. Es decir, quiere que read . showsea ​​la identidad (para los tipos que son una instancia de Showy Read) y esa show . reades la identidad en el rango de show(es decir show . read . show == show)

Tener un Maybeen el tipo de readrompe la simetría con show :: a -> String.

yatima2975
fuente
¡Gracias por agregar un nuevo ángulo! Eso tiene sentido. Pero para lograrlo claramente, ¿no tendría sentido que tanto show como read produzcan un tipo distinto, digamos "ParseableString"?
Bilal Barakat
1
@BilalBarakat: El tipo diferenciado podría ser newtype ValidShow a = ValidShow String. El tipo fantasma lo hace más seguro para los tipos.
yairchu
9
Es un punto interesante, pero en última instancia, una falsa simetría. Los programadores deben valorar la corrección sobre la estética.
Matt Fenwick
1
@yairchu No fue inmediatamente obvio para mí lo que querías decir sobre el tipo fantasma, así que lo aclararé en caso de que alguien más esté confundido como yo. Tiene la intención de algo como showThing :: Show a => a -> ValidShow ay readThing :: Read a => ValidShow a -> a, para que el tipo de cosa que se mostró se recuerde en el objeto ValidShow. De esta forma no puedes escribir readThing (showThing True) :: String.
amalloy
12

Como señaló @augustss, puede crear su propia función de lectura segura. Sin embargo, sureadMaybe no es completamente consistente con read, ya que no ignora los espacios en blanco al final de una cadena. (Cometí este error una vez, no recuerdo bien el contexto)

Mirando la definición de lectura en el informe Haskell 98 , podemos modificarla para implementar una readMaybeque sea perfectamente consistente con read, y esto no es demasiado inconveniente porque todas las funciones de las que depende están definidas en el Preludio:

readMaybe        :: (Read a) => String -> Maybe a
readMaybe s      =  case [x | (x,t) <- reads s, ("","") <- lex t] of
                         [x] -> Just x
                         _   -> Nothing
lpsmith
fuente
1
¡Gracias! +1 por alertarme sobre el problema de los espacios en blanco, que no se había hecho explícito antes.
Bilal Barakat
3
Tenga en cuenta que si solo usa el safepaquete, obtiene una versión correcta de readMaybedisponible (se llama readMayy es idéntica a esta versión.
Neil Mitchell
8

¡Esta función (llamada readMaybe) está ahora en el preludio de Haskell! (A partir de la base actual - 4.6)

amindfv
fuente
2
Bueno, el texto vinculado dice que está en Text. Lee y no en Prelude (puede haber cambiado), sin embargo, ¡aún me ayudó!
Kapichu