Эквивалент метода Фреге getLine и read в Haskell
-
13-11-2019 - |
Вопрос
Есть ли эквивалент Фреге Хаскеля? getLine
и read
анализировать ввод с консоли в стандартной библиотеке?
На данный момент я делаю это так:
import frege.IO
getLine :: IO String
getLine = do
isin <- stdin
isrin <- IO.InputStreamReader.new isin
brin <- IO.BufferedReader.fromISR isrin
line <- brin.readLine
return $ fromExceptionMaybe line
fromExceptionMaybe :: Exception (Maybe a) -> a
fromExceptionMaybe (Right (Just r)) = r
fromExceptionMaybe (Right _) = error "Parse error on input"
fromExceptionMaybe (Left l) = error l.getMessage
pure native parseInt java.lang.Integer.parseInt :: String -> Int
main _ = do
line <- getLine
println $ parseInt line
Обновлять:
Фреге был развит, и теперь у нас есть getLine
в самой стандартной библиотеке.Что касается read
, у нас есть методы преобразования для String.Теперь исходная проблема проста:
main _ = do
line <- getLine
println line.atoi
Более подробную информацию смотрите в ответе Инго ниже.
Решение
Обновлять:Поддержка ввода-вывода в более поздних версиях Frege
Начиная с версии 3.21.80, в стандартных библиотеках улучшена поддержка ввода-вывода:
- Среда выполнения обеспечивает
stdout
иstderr
(буферизованный, кодировка UTF8)java.io.PrintWriters
завернутыйjava.lang.System.out
иjava.lang.System.err
) иstdin
(расшифровка UTF8java.io.BufferedReader
завернутыйjava.lang.System.in
) - Функции
print
,println
,putStr
,putChar
написатьstdout
getChar
иgetLine
читать изstdin
и выдавать исключения в конце файла.- Эквиваленты Фреге для классов Java, таких как
PrintWriter
,BufferedWriter
и т. д.определены в модулеJava.IO
, который импортируется автоматически.При этом поддерживаются более базовые функции.Например,BufferedReader.readLine
имеет возвращаемый типIO (Maybe String)
и сигнализирует об окончании файла, возвращаяNothing
, как и его аналог в Java, который возвращаетnull
в таких случаях.
Вот краткий пример программы, реализующей базовый grep:
--- A simple grep
module examples.Grep where
--- exception thrown when an invalid regular expression is compiled
data PatternSyntax = native java.util.regex.PatternSyntaxException
derive Exceptional PatternSyntax
main [] = stderr.println "Usage: java examples.Grep regex [files ...]"
main (pat:xs) = do
rgx <- return (regforce pat)
case xs of
[] -> grepit rgx stdin
fs -> mapM_ (run rgx) fs
`catch` badpat where
badpat :: PatternSyntax -> IO ()
badpat pse = do
stderr.println "The regex is not valid."
stderr.println pse.getMessage
run regex file = do
rdr <- utf8Reader file
grepit regex rdr
`catch` fnf where
fnf :: FileNotFoundException -> IO ()
fnf _ = stderr.println ("Could not read " ++ file)
grepit :: Regex -> BufferedReader -> IO ()
grepit pat rdr = loop `catch` eof `finally` rdr.close
where
eof :: EOFException -> IO ()
eof _ = return ()
loop = do
line <- rdr.getLine
when (line ~ pat) (println line)
loop
Поскольку Фреге все еще довольно новичок, поддержка библиотеки, по общему признанию, все еще отсутствует, несмотря на прогресс, уже достигнутый в самых основных областях, таких как списки и монады.
Кроме того, хотя целью является обеспечение высокой степени совместимости с Haskell, особенно в системе ввода-вывода и вообще в темах, связанных с системой низкого уровня, существует противоречие:Стоит ли нам идти по пути Java или действительно попытаться подражать пути Haskell (на который, в свою очередь, очевидно влияет то, что доступно в стандартных библиотеках C/POSIX).
В любом случае, к сожалению, область ввода-вывода — это, пожалуй, самая недоработанная область библиотеки Фреге.Это также связано с тем, что относительно легко быстро написать собственные объявления функций для нескольких методов Java, которые могут понадобиться в индивидуальном порядке, вместо того, чтобы тратить время на разработку хорошо продуманной библиотеки.
Кроме того, до сих пор не существует класса Read.В качестве замены, пока это не будет исправлено, тип String имеет функции для анализа всех типов чисел (на основе методов Java parseXXX()).
(Примечание:Поскольку в моих сутках тоже всего 24 часа, а у меня есть семья, собака и работа, о которой нужно заботиться, я был бы очень рад, если бы у меня было больше участников, которые помогут сделать систему Фреге лучше.)
Что касается вашего кода:Да, я считаю правильным выполнять весь символьный ввод-вывод через интерфейсы Reader и Writer.Ваш пример также показывает, что необходимы удобные функции для получения устройства чтения стандартного ввода.То же самое справедливо и для средства записи стандартного вывода.
Однако, когда вам нужно прочитать более 1 строки, я бы определенно создал средство чтения в основной функции и передал его действиям по обработке ввода.