Haskell: читать число (целое или с плавающей точкой) - PullRequest
5 голосов
/ 04 марта 2012

Я использую эту реализацию maybeRead:

maybeRead :: (Read a) => String -> Maybe a
maybeRead = fmap fst . listToMaybe . filter (null . dropWhile isSpace . snd) . reads

и мою собственную функцию getNum, которая запрашивает, пока не получит действительный ввод:

getNum :: (Num a, Read a) => String -> IO a
getNum s = do
    putStr s
    input <- fmap maybeRead getLine
    if isNothing input
        then getNum s
        else return $ fromJust input

Однако, если я введу5.2 он воспринимает это как плохой ввод. Почему?В моем коде ноль вхождений Int и Integer.Я использую только Num, так как я хочу принять любой тип числа.

Если я назову его явно как getNum "Enter a number: " :: IO Double, тогда это работает.Должен ли я сделать это?Разве система типов Хаскелла обманывает меня, заставляя меня думать, что я смогу сделать это, когда это действительно невозможно без полной динамической типизации?Если так, то почему мой код даже компилируется;почему он принимает целые числа?

1 Ответ

13 голосов
/ 04 марта 2012

Ваша функция действительно примет Integer, Float или любой другой Num экземпляр.Однако, какой тип он принимает, и, соответственно, то, как он анализирует String, не определяется входом , который он получает , это определяется , какой тип результата должен быть на основечто вы делаете с ним.

Скажем, вы используете getNum и передаете полученное значение чему-то, что требует Float;в этом случае он будет анализировать значение Float.Если вы передадите его чему-то, что вместо этого требует Integer, он проанализирует это.

Что касается причины, по которой он принимает Integer, существует система по умолчанию для неоднозначных типов , указанная вHaskell Report , а правила гласят, что для неоднозначного типа с ограничением Num по умолчанию должно быть Integer.

...