O equivalente de Frege ao getLine e read de Haskell
-
13-11-2019 - |
Pergunta
Existe algum equivalente de Frege ao de Haskell? getLine
e read
analisar a entrada do console na biblioteca padrão?
Atualmente estou fazendo assim:
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
Atualizar:
Frege evoluiu então agora temos getLine
na própria biblioteca padrão.Quanto a read
, temos métodos de conversão em String.Agora, o problema original é simplesmente,
main _ = do
line <- getLine
println line.atoi
Veja a resposta de Ingo abaixo para mais detalhes.
Solução
Atualizar:Suporte de E/S em versões mais recentes do Frege
A partir da versão 3.21.80, temos melhor suporte de E/S nas bibliotecas padrão:
- O tempo de execução fornece
stdout
estderr
(bufferizado, codificação UTF8java.io.PrintWriters
enroladojava.lang.System.out
ejava.lang.System.err
) estdin
(decodificação UTF8java.io.BufferedReader
enroladojava.lang.System.in
) - Funções
print
,println
,putStr
,putChar
escrever parastdout
getChar
egetLine
leia destdin
e lançar exceções no final do arquivo.- Os equivalentes de Frege para classes Java como
PrintWriter
,BufferedWriter
etc.são definidos no móduloJava.IO
, que é importado automaticamente.Com isso, funcionalidades mais básicas são suportadas.Por exemplo,BufferedReader.readLine
tem um tipo de retorno deIO (Maybe String)
e sinaliza o fim do arquivo retornandoNothing
, como sua contraparte Java, que retornanull
em tais casos.
Aqui está um pequeno exemplo de programa que implementa um grep básico:
--- 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
Como Frege ainda é bastante novo, é certo que o suporte da biblioteca ainda é insuficiente, apesar do progresso que já é feito nas áreas mais básicas, como Listas e Mônadas.
Além disso, embora a intenção seja ter um alto grau de compatibilidade com Haskell, especialmente no sistema IO e geralmente nos tópicos relacionados ao sistema de baixo nível, há uma tensão:Deveríamos preferir seguir o caminho Java ou deveríamos realmente tentar emular o caminho de Haskell (que por sua vez é obviamente influenciado pelo que está disponível nas bibliotecas C/POSIX padrão).
De qualquer forma, infelizmente, a área de IO é provavelmente a área mais subdesenvolvida da biblioteca de Frege.Isso também ocorre porque é relativamente fácil escrever rapidamente declarações de funções nativas para um punhado de métodos Java necessários de maneira ad hoc, em vez de perder tempo desenvolvendo uma biblioteca bem elaborada.
Além disso, uma classe Read não existe até agora.Como substituto até que isso seja corrigido, o tipo String possui funções para analisar todos os tipos de números (com base nos métodos Java parseXXX()).
(Nota:Como meus dias também têm apenas 24h e tenho uma família, um cachorro e um trabalho para cuidar, ficaria muito feliz em ter mais colaboradores que ajudem a melhorar o sistema Frege.)
Em relação ao seu código:Sim, acho certo fazer todas as E/S baseadas em caracteres por meio das interfaces do Reader e do Writer.Seu exemplo mostra também que são necessárias funções de conveniência para obter um leitor de entrada padrão.O mesmo vale para o gravador de saída padrão.
Porém, quando você precisasse ler mais de uma linha, eu definitivamente criaria o leitor na função principal e o passaria para as ações de processamento de entrada.