Почему Prelude.read Haskell не возвращает Maybe?

108

Есть ли веская причина, по которой тип Prelude.read

read :: Read a => String -> a

вместо возврата Maybeзначения?

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

Поскольку строка может не поддаваться синтаксическому анализу Haskell, не будет ли последнее более естественным?

Или даже Either String a, где Leftбы содержалась исходная строка, если бы она не анализировалась, и Rightрезультат, если бы это было?

Редактировать:

Я не пытаюсь заставить других написать за меня соответствующую оболочку. Просто ищу подтверждения, что это безопасно.

Билал Баракат
источник
14
Почему не takeпринимает Num a => a? Почему используется специальный случай fmapдля списков? Почему Functorне требуется для Monadинстансов? Я ожидаю, что ответ будет аналогичен ответам на эти и связанные с ними вопросы.
3
Вот почему я сформулировал это так, как я это сделал, оставив открытым вариант, что для этого нет веской причины. Хотя я также подозреваю, что этого может и не быть, как и в случае с хорошо известными примерами, которые вы приводите, стоит попросить убедиться, что написание моей собственной оболочки не создаст непредвиденных проблем в дальнейшем.
Билал Баракат
Надеюсь, readMaybeфункция скоро будет добавлена.
август
Хорошие замечания @delnan, но не должно takeбыть Integral n => n -> [a] -> [a]?
Doug McClean
@DougMcClean: Да, на самом деле должно быть Integral, а не Num- мозговой пердун.

Ответы:

106

Изменить : Начиная с GHC 7.6, readMaybeон доступен в Text.Readмодуле в базовом пакете вместе с readEither: http://hackage.haskell.org/packages/archive/base/latest/doc/html/Text-Read.html#v: читать


Отличный вопрос! Сам тип чтения в ближайшее время не изменится, потому что это может сломать многое. Однако должна быть maybeReadфункция.

Почему нет? Ответ - «инерция». В '08 была дискуссия, которая была сорвана обсуждением «провала».

Хорошая новость заключается в том, что люди были достаточно убеждены, чтобы избавиться от неудач в библиотеках. Плохая новость в том, что предложение потерялось в беспорядке. Там должна быть такой функция, хотя один легко писать (и есть миллиард очень похожих версии плавающий вокруг много баз коды).

См. Также это обсуждение .

Лично я использую версию из безопасного пакета .

sclv
источник
30

Да, было бы удобно с функцией чтения, которая возвращает Maybe. Вы можете сделать его сами:

readMaybe :: (Read a) => String -> Maybe a
readMaybe s = case reads s of
              [(x, "")] -> Just x
              _ -> Nothing
август
источник
3
Спасибо! Надеюсь, редактирование не звучит неблагодарно! :) Просто хочу прояснить, что я прошу не из-за лени ...
Билал Баракат
6
Если @augustss не может его предоставить, лучшего ответа может не быть.
John L
2
Я не думаю, что в первоначальном дизайне когда-либо обсуждалась возможная версия. Многие из этих вещей становятся очевидными с опытом, но их трудно предсказать.
августа
Причина , которая читает возвращает список для случая , когда есть несколько действительных разбирает. Случай Maybe занимает промежуточное положение между чтением и чтением.
Chris Kuklewicz
Я думаю, для этого нужен Read aкласс типов:readMaybe :: Read a => String -> Maybe a
Дэвид Чепак
15

Помимо инерции и / или изменчивого понимания, другой причиной может быть то, что эстетически приятно иметь функцию, которая может действовать как своего рода обратная show. То есть вы хотите, чтобы read . showэто идентификатор (для типов, являющихся экземпляром Showи Read), и это show . readидентификатор в диапазоне show(т.е. show . read . show == show)

Имея Maybeв виду readнарушает симметрию с show :: a -> String.

yatima2975
источник
Спасибо за добавление нового ракурса! В этом есть смысл. Но для того, чтобы добиться этого чисто, разве не имеет смысла, чтобы и show, и read производили отдельный тип, например ParseableString?
Bilal Barakat
1
@BilalBarakat: Другой тип может быть newtype ValidShow a = ValidShow String. Фантомный тип делает его более безопасным.
yairchu
9
Это интересный момент, но в конечном итоге ложная симметрия. Программисты должны ценить правильность выше эстетики.
Мэтт Фенвик,
1
@yairchu Для меня не сразу было очевидно, что вы имели в виду, говоря о фантомном типе, поэтому я поясню, если кто-то еще запутается, как я. Вы имеете в виду что-то вроде showThing :: Show a => a -> ValidShow aи readThing :: Read a => ValidShow a -> a, чтобы тип показанного объекта запомнился в объекте ValidShow. Так писать нельзя readThing (showThing True) :: String.
amalloy
12

Как отметил @augustss, вы можете создать свою собственную функцию безопасного чтения. Однако его использование readMaybeне полностью соответствует read, поскольку оно не игнорирует пробелы в конце строки. (Я однажды допустил эту ошибку, не совсем помню контекст)

Глядя на определение чтения в отчете Haskell 98 , мы можем изменить его, чтобы реализовать readMaybeполностью согласованный с ним read, и это не слишком неудобно, потому что все функции, от которых он зависит, определены в Prelude:

readMaybe        :: (Read a) => String -> Maybe a
readMaybe s      =  case [x | (x,t) <- reads s, ("","") <- lex t] of
                         [x] -> Just x
                         _   -> Nothing
lpsmith
источник
1
Спасибо! +1 за то, что предупредил меня о проблеме с пробелами, о которой раньше не сообщалось.
Билал Баракат
3
Обратите внимание: если вы просто используете safeпакет, вы получите правильную readMaybeдоступную версию (она называется, readMayи она идентична этой версии.
Нил Митчелл,
8

Эта функция (вызываемая readMaybe) теперь находится в прелюдии к Haskell! (По текущей базе - 4,6)

amindfv
источник
2
Что ж, связанный текст говорит, что это в Text.Read, а не в Prelude (возможно, изменилось), однако мне все равно помогло!
Капичу