Причина этого заключается в том, что строка "2,2"
не может быть преобразована в Int
: это цифра, за которой следует запятая, за которой следует цифра.Int
анализируется необязательным знаком минус, за которым следуют некоторые цифры и некоторые дополнительные возможности, такие как шестнадцатеричные числа, но пока давайте их игнорировать.
Однако указанная вами подпись типа для f
неверно, исходя из ожидаемого результата.Ваш тип вывода выглядит как список списков из Int
с, поэтому [[Int]]
.Это означает, что вы должны указать f
как:
f :: [String] -> <b>[[Int]]</b>
f = ...
Таким образом, нам нужно прочитать каждый String
в [Int]
.Мы не можем использовать read
непосредственно здесь, так как read
при [Int]
ожидает, что строка начинается и заканчивается квадратными скобками .Однако мы можем добавить их вручную, например:
f :: [String] -> [[Int]]
f = map (<b>\s -> read ('[' : s ++ "]")</b>)
или без очков версия:
f :: [String] -> [[Int]]
f = map (<b>read . ('[' :) . (++ "]")</b>)
Например:
Prelude> f ["2","2","1","2,2","1"]
[[2],[2],[1],[2,2],[1]]
В направлении безопаснее парсинга с readMaybe
парсинг от String
с, как описано выше, конечно, не очень " безопасно ", так как это возможночто String
не соответствует формату.Мы можем сделать это более безопасным и использовать, например, readMaybe :: Read a => String -> Maybe a
:
import Text.Read(<b>readMaybe</b>)
f :: [String] -> [<b>Maybe</b> [Int]]
f = map (<b>readMaybe</b> . ('[' :) . (++ "]"))
Например:
Prelude Text.Read> f ["2", "3;2", "4,7,3", "bla"]
[Just [2],Nothing,Just [4,7,3],Nothing]
мы можем опуститьнапример, ошибочные чтения с использованием catMaybes :: [Maybe a] -> [a]
:
import Data.Maybe(<b>catMaybes</b>)
import Text.Read(readMaybe)
f :: [String] -> [[Int]]
f = <b>catMaybes</b> . map (readMaybe . ('[' :) . (++ "]"))
Например:
Prelude Data.Maybe Text.Read> f ["2", "3;2", "4,7,3", "bla"]
[[2],[4,7,3]]
или как @dfeuer сказал, что мы можем использовать traverse :: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b)
, чтобы вернуть [[Int]]
результат, заключенный в Just
, если все синтаксический анализ завершился успешно, и Nothing
в противном случае:
import Text.Read(readMaybe)
f :: [String] -> <b>Maybe</b> [[Int]]
f = <b>traverse</b> (readMaybe . ('[' :) . (++ "]"))
Например:
Prelude Text.Read> f ["2","2","1","2,2","1"]
Just [[2],[2],[1],[2,2],[1]]
Prelude Text.Read> f ["2", "3;2", "4,7,3", "bla"]
Nothing
Анализировать с сообщениями об ошибках с помощью readEither
Мы можем получить сообщение об ошибке, заключенное в Left
в случае сбоя синтаксического анализа с использованием readEither :: Read a => String -> Either String a
:
import Text.Read(<b>readEither</b>)
f :: [String] -> [<b>Either String</b> [Int]]
f = map (<b>readEither</b> . ('[' :) . (++ "]"))
Например:
Prelude Text.Read> f ["2", "3;2", "4,7,3", "bla"]
[Right [2],Left "Prelude.read: no parse",Right [4,7,3],Left "Prelude.read: no parse"]
и использованием traverse
таким же образом, чтобы получить сообщение об ошибке, заключенное в Left
или полный результат в Right
:
import Text.Read(readEither)
f :: [String] -> <b>Either String</b> [[Int]]
f = <b>traverse</b> (readEither . ('[' :) . (++ "]"))
Например:
Prelude Text.Read> f ["2","2","1","2,2","1"]
Right [[2],[2],[1],[2,2],[1]]
Prelude Text.Read> f ["2", "3;2", "4,7,3", "bla"]
Left "Prelude.read: no parse"
Здесь, как @Dfeuer говорит, что на самом деле не показывает много информации.Однако существуют парсеры, которые могут предоставить более информативные ошибки синтаксического анализа.