Dlaczego Prelude.read Haskella nie zwraca odpowiedzi „Może”?

108

Czy istnieje dobry powód, dla którego jest to typ Prelude.read

read :: Read a => String -> a

zamiast zwracać Maybewartość?

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

Skoro łańcuch Haskell może nie dać się przeanalizować, czy to drugie nie byłoby bardziej naturalne?

Lub nawet Either String a, gdzie Leftzawierałby oryginalny ciąg, gdyby nie został przeanalizowany, a Rightwynik, gdyby tak się stało?

Edytować:

Nie próbuję nakłonić innych do napisania dla mnie odpowiedniego opakowania. Po prostu szukam pewności, że można to bezpiecznie zrobić.

Bilal Barakat
źródło
14
Dlaczego nie takeakceptuje żadnego Num a => a? Dlaczego istnieje specjalny przypadek fmapdla list? Dlaczego Functornie jest to wymagane w Monadprzypadku instancji? Oczekuję, że odpowiedź będzie podobna do odpowiedzi na te i pokrewne pytania.
3
Cóż, dlatego sformułowałem to tak, jak to zrobiłem, pozostawiając otwartą opcję, że nie ma dobrego powodu. Chociaż podejrzewam również, że może ich nie być, tak jak w przypadku dobrze znanych przykładów, które podajesz, warto poprosić o upewnienie się, że napisanie własnego opakowania nie spowoduje nieprzewidzianych problemów na późniejszym etapie.
Bilal Barakat
Mam nadzieję, że readMaybewkrótce zostanie dodana funkcja.
sierpień
Zalety @delnan, ale nie powinno takebyć Integral n => n -> [a] -> [a]?
Doug McClean
@DougMcClean: Tak, właściwie powinno być Integral, a nie Num- pierdnięcie mózgiem.

Odpowiedzi:

106

Edycja : Od wersji GHC 7.6, readMaybejest dostępna w Text.Readmodule w pakiecie podstawowym, wraz z readEither: http://hackage.haskell.org/packages/archive/base/latest/doc/html/Text-Read.html#v: przeczytajMoże


Świetne pytanie! Sam rodzaj odczytu nie zmieni się w najbliższym czasie, ponieważ to zepsułoby wiele rzeczy. Jednak nie powinno być maybeReadfunkcja.

Dlaczego nie ma? Odpowiedź brzmi „bezwładność”. W 2008 roku odbyła się dyskusja, która została zakłócona przez dyskusję na temat „porażki”.

Dobra wiadomość jest taka, że ​​ludzie byli wystarczająco przekonani, aby zacząć unikać porażek w bibliotekach. Zła wiadomość jest taka, że ​​propozycja zaginęła w tasowaniu. Nie powinna być taka funkcja, choć jeden jest łatwo napisać (i istnieją setki tego bardzo podobnych wersjach pływających wokół wiele codebases).

Zobacz także tę dyskusję .

Osobiście korzystam z wersji z bezpiecznego pakietu .

sclv
źródło
30

Tak, przydałaby się funkcja odczytu, która zwraca wartość Maybe. Możesz zrobić to sam:

readMaybe :: (Read a) => String -> Maybe a
readMaybe s = case reads s of
              [(x, "")] -> Just x
              _ -> Nothing
augustss
źródło
3
Dziękuję Ci! Mam nadzieję, że montaż nie brzmi niewdzięcznie! :) Chcę tylko wyjaśnić, że nie pytam z lenistwa ...
Bilal Barakat
6
Jeśli @augustss nie może tego zapewnić, lepsza odpowiedź może nie istnieć.
John L
2
Nie sądzę, aby kiedykolwiek omawiano wersję może w oryginalnym projekcie. Wiele z tych rzeczy staje się oczywistych wraz z doświadczeniem, ale mogą być trudne do przewidzenia.
sierpień
Powodem , że czyta Zwraca listę jest dla przypadku, gdy istnieje wiele ważnych Analizuje. Przypadek Może jest pośredni między odczytem a odczytem.
Chris Kuklewicz
Myślę, że to wymaga Read atypeklasy:readMaybe :: Read a => String -> Maybe a
David Tchepak
15

Oprócz inercji i / lub zmieniających się spostrzeżeń, innym powodem może być to, że estetycznie przyjemne jest posiadanie funkcji, która może działać jako coś w rodzaju odwrotności show. Oznacza to, że chcesz, aby read . showbyła to tożsamość (dla typów, które są wystąpieniem Showi Read) i to show . readjest tożsamość w zakresie show(tj. show . read . show == show)

Posiadanie Maybew typie readłamie symetrię z show :: a -> String.

yatima2975
źródło
Dzięki za dodanie nowego kąta! To ma sens. Ale żeby to osiągnąć czysto, czy nie miałoby sensu, gdyby zarówno show, jak i read tworzyły odrębny typ, na przykład „ParseableString”?
Bilal Barakat
1
@BilalBarakat: Może to być odrębny typ newtype ValidShow a = ValidShow String. Typ fantomowy czyni go bardziej bezpiecznym.
yairchu
9
To interesujący punkt, ale ostatecznie fałszywa symetria. Programiści powinni przedkładać poprawność ponad estetykę.
Matt Fenwick
1
@yairchu Nie było dla mnie od razu oczywiste, co miałeś na myśli mówiąc o typie widma, więc wyjaśnię, na wypadek gdyby ktoś inny był zdezorientowany tak jak ja. Zamierzasz coś w rodzaju showThing :: Show a => a -> ValidShow ai readThing :: Read a => ValidShow a -> a, aby typ rzeczy, który został pokazany, został zapamiętany w obiekcie ValidShow. W ten sposób nie możesz pisać readThing (showThing True) :: String.
amalloy
12

Jak zauważył @augustss, możesz stworzyć własną funkcję bezpiecznego odczytu. Jednak jego readMaybenie jest całkowicie spójny z odczytem, ​​ponieważ nie ignoruje białych znaków na końcu ciągu. (Raz popełniłem ten błąd, nie całkiem pamiętam kontekstu)

Patrząc na definicję read w raporcie Haskell 98 , możemy ją zmodyfikować tak, aby zaimplementować w readMaybepełni spójną read, a nie jest to zbyt uciążliwe, ponieważ wszystkie funkcje, od których zależy, są zdefiniowane w Prelude:

readMaybe        :: (Read a) => String -> Maybe a
readMaybe s      =  case [x | (x,t) <- reads s, ("","") <- lex t] of
                         [x] -> Just x
                         _   -> Nothing
lpsmith
źródło
1
Dzięki! +1 za ostrzeżenie mnie o problemie z białymi znakami, który wcześniej nie został wyjaśniony.
Bilal Barakat
3
Zwróć uwagę, że jeśli tylko użyjesz safepakietu, otrzymasz poprawną wersję readMaybedostępnej (nazywa się readMayi jest identyczna z tą wersją.
Neil Mitchell
8

Ta funkcja (nazywana readMaybe) jest teraz w preludium Haskella! (W obecnej bazie - 4,6)

amindfv
źródło
2
Cóż, tekst z linkiem mówi, że jest w tekście, przeczytaj, a nie w Preludium (mogło się zmienić), jednak nadal mi to pomogło!
Kapichu