Perché Haskell's Prelude.read non restituisce un Forse?


108

C'è una buona ragione per cui il tipo di Prelude.read è

read :: Read a => String -> a

piuttosto che restituire un Maybevalore?

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

Dal momento che la stringa potrebbe non essere analizzabile Haskell, quest'ultima non sarebbe più naturale?

O anche un Either String a, dove Leftconterrebbe la stringa originale se non analizza, e Rightil risultato se lo facesse?

Modificare:

Non sto cercando di convincere altri a scrivere un wrapper corrispondente per me. Sto solo cercando di rassicurarlo sul fatto che sia sicuro farlo.


14
Perché non ne takeaccetta nessuno Num a => a? Perché esiste un caso speciale di fmapelenchi per? Perché Functornon è richiesto per le Monadistanze? Mi aspetto che la risposta sia simile alle risposte a queste e ad altre domande correlate.

3
Bene, è per questo che l'ho formulato nel modo in cui ho fatto, lasciando aperta l'opzione che non c'è una buona ragione. Anche se sospetto che potrebbe non esserci, come per i ben noti esempi che fornisci, vale la pena chiedere di assicurarti che scrivere il mio wrapper non crei problemi imprevisti a valle.
Bilal Barakat

Spero readMaybeche presto venga aggiunta una funzione.
agosto

Buoni punti @delnan, ma non dovrebbe takeessere Integral n => n -> [a] -> [a]?
Doug McClean

@DougMcClean: Sì, in realtà dovrebbe essere Integral, non Num- scoreggia cerebrale.

Risposte:


106

Modifica : a partire da GHC 7.6, readMaybeè disponibile nel Text.Readmodulo nel pacchetto base, insieme a readEither: http://hackage.haskell.org/packages/archive/base/latest/doc/html/Text-Read.html#v: readMaybe


Ottima domanda! Il tipo di lettura in sé non cambierà presto perché ciò interromperebbe molte cose. Tuttavia, dovrebbe esserci una maybeReadfunzione.

Perché non c'è? La risposta è "inerzia". C'è stata una discussione nel '08 che è stata deragliata da una discussione sul "fallimento".

La buona notizia è che le persone erano sufficientemente convinte da iniziare ad allontanarsi dal fallimento nelle biblioteche. La cattiva notizia è che la proposta si è persa nella confusione. Ci dovrebbe essere tale funzione una, anche se uno è facile da scrivere (e ci sono un'infinità di versioni molto simili girano molte basi di codice).

Vedi anche questa discussione .

Personalmente, utilizzo la versione dal pacchetto sicuro .


30

Sì, sarebbe utile con una funzione di lettura che restituisce Forse. Puoi crearne uno tu stesso:

readMaybe :: (Read a) => String -> Maybe a
readMaybe s = case reads s of
              [(x, "")] -> Just x
              _ -> Nothing

3
Grazie! Spero che la modifica non sembri ingrata! :) Voglio solo chiarire che non sto chiedendo per pigrizia ...
Bilal Barakat

6
Se @augustss non è in grado di fornirlo, potrebbe non esistere una risposta migliore.
John L

2
Non credo che una versione forse sia mai stata discussa nel design originale. Molte di queste cose diventano ovvie con l'esperienza, ma possono essere difficili da prevedere.
agosto

Il motivo per cui reads restituisce un elenco è il caso in cui sono presenti più analisi valide. Il caso Forse è intermedio tra letture e letture.
Chris Kuklewicz

Penso che questo richieda il Read atypeclass:readMaybe :: Read a => String -> Maybe a
David Tchepak,

15

A parte l'inerzia e / o le mutevoli intuizioni, un altro motivo potrebbe essere che è esteticamente piacevole avere una funzione che può agire come una sorta di inverso di show. Cioè, vuoi che read . showsia l'identità (per i tipi che sono un'istanza di Showand Read) e che show . readsia l'identità nell'intervallo di show(ie show . read . show == show)

Avere un Maybenel tipo readrompe la simmetria con show :: a -> String.


Grazie per aver aggiunto una nuova angolazione! Questo ha senso. Ma per ottenere ciò in modo pulito, non avrebbe senso avere sia show che read produrre un tipo distinto, ad esempio "ParseableString"?
Bilal Barakat

1
@BilalBarakat: il tipo distinto potrebbe essere newtype ValidShow a = ValidShow String. Il tipo fantasma lo rende più sicuro dai tipi.
yairchu

9
È un punto interessante, ma alla fine una falsa simmetria. I programmatori dovrebbero valutare la correttezza rispetto all'estetica.
Matt Fenwick

1
@yairchu Non è stato immediatamente ovvio per me cosa intendevi per il tipo fantasma, quindi chiarirò nel caso qualcun altro fosse confuso come me. Intendi qualcosa come showThing :: Show a => a -> ValidShow ae readThing :: Read a => ValidShow a -> a, in modo che il tipo di oggetto che è stato mostrato venga ricordato nell'oggetto ValidShow. In questo modo non puoi scrivere readThing (showThing True) :: String.
amalloy

12

Come ha sottolineato @augustss, puoi creare la tua funzione di lettura sicura. Tuttavia, il suo readMaybenon è completamente coerente con la lettura, in quanto non ignora gli spazi bianchi alla fine di una stringa. (Ho commesso questo errore una volta, non ricordo bene il contesto)

Guardando la definizione di read nel report Haskell 98 , possiamo modificarla per implementarne una readMaybeche sia perfettamente coerente read, e questo non è troppo scomodo perché tutte le funzioni da cui dipende sono definite nel Prelude:

readMaybe        :: (Read a) => String -> Maybe a
readMaybe s      =  case [x | (x,t) <- reads s, ("","") <- lex t] of
                         [x] -> Just x
                         _   -> Nothing

1
Grazie! +1 per avermi avvertito del problema degli spazi bianchi, che non era stato reso esplicito prima.
Bilal Barakat

3
Nota che se usi solo il safepacchetto, ottieni una versione corretta di readMaybedisponibile (si chiama readMayed è identico a questa versione.
Neil Mitchell

8

Questa funzione (chiamata readMaybe) è ora nel preludio di Haskell! (Alla base attuale - 4.6)


2
Bene, il testo collegato dice che è in Text Read e non in Prelude (potrebbe essere cambiato), tuttavia, mi ha comunque aiutato!
Kapichu
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.