Frege est l'équivalent de Haskell's Getline et Read
-
13-11-2019 - |
Question
Y a-t-il l'équivalent de Frege de Haskell getLine
et read
Pour analyser les entrées de la console dans la bibliothèque standard?
Actuellement, je le fais comme ceci:
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
Mise à jour:
Frege a évolué alors maintenant nous avons getLine
dans la bibliothèque standard elle-même. Pour ce qui est de read
, nous avons des méthodes de conversion sur la chaîne. Maintenant, le problème d'origine est simplement,
main _ = do
line <- getLine
println line.atoi
Voir la réponse d'Ingo ci-dessous pour plus de détails.
La solution
MISE À JOUR: Prise en charge des E / S dans les versions plus récentes de Frege
À partir de la version 3.21.80, nous avons une meilleure prise en charge d'E / S dans les bibliothèques standard:
- Le temps d'exécution fournit
stdout
etstderr
(Encodage tamponné, UTF8java.io.PrintWriters
enroulé autourjava.lang.System.out
etjava.lang.System.err
) etstdin
(Décodage UTF8java.io.BufferedReader
enroulé autourjava.lang.System.in
) - Les fonctions
print
,println
,putStr
,putChar
écrire àstdout
getChar
etgetLine
Lire destdin
et lancer des exceptions à la fin du fichier.- Les équivalents Frege pour les classes Java comme
PrintWriter
,BufferedWriter
etc. sont définis dans le moduleJava.IO
, qui est automatiquement importé. Avec cela, des fonctionnalités plus de base sont prises en charge. Par exemple,BufferedReader.readLine
a un type de retour deIO (Maybe String)
et signale la fin du fichier en retournantNothing
, comme son homologue Java, qui revientnull
dans ces cas.
Voici un court exemple de programme qui implémente un Grep de base:
--- 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
Parce que Frege est encore assez nouveau, le support de la bibliothèque est certes encore manquant, malgré les progrès qui se font déjà dans les domaines les plus élémentaires, comme les listes et les monades.
De plus, alors que l'intention est d'avoir un degré élevé de compatibilité avec Haskell, en particulier dans le système IO et généralement dans les sujets liés au système de bas niveau, il y a une tension: si nous avons plutôt emprunter la voie Java ou si nous essayons vraiment de imitez la voie de Haskell (qui est à son tour évidemment influencé par ce qui est disponible dans les bibliothèques C / POSIX standard).
Quoi qu'il en soit, la chose IO est probablement la zone la plus sous-développée de la bibliothèque Frege, malheureusement. Cela est également dû au fait qu'il est relativement facile d'écrire rapidement les déclarations de fonctions natives pour une poignée de méthodes Java dont on aurait besoin de manière ad hoc, au lieu de prendre le temps de développer une bibliothèque puits.
De plus, une classe de lecture n'existe pas jusqu'à présent. En tant que substitut jusqu'à ce que cela soit corrigé, le type de chaîne a des fonctions pour analyser tous les types de nombres (basés sur les méthodes Java Parsexxx ()).
(Note latérale: Parce que mes journées n'ont également que 24h et j'ai une famille, un chien et un travail à qui nous soucier, je serais très heureux d'avoir plus de contributeurs qui aident à améliorer le système Frege.)
En ce qui concerne votre code: oui, je pense qu'il est juste de faire toutes les E / S basées sur des personnages via les interfaces lecteur et l'écrivain. Votre exemple montre également que les fonctions de commodité pour obtenir un lecteur d'entrée standard sont nécessaires. Il en va de même pour l'écrivain de sortie standard.
Cependant, lorsque vous auriez besoin de lire plus d'une ligne, je créerais définitivement le lecteur dans la fonction principale et le transmettrais aux actions de traitement des entrées.