Frege の Haskell の getLine および read に相当します。
-
13-11-2019 - |
質問
Haskell に相当する Frege はありますか 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
詳細については、以下の Ingo の回答を参照してください。
解決
アップデート:Frege のより新しいバージョンでの I/O サポート
バージョン 3.21.80 では、標準ライブラリの I/O サポートが向上しています。
- ランタイムが提供するのは、
stdout
そしてstderr
(バッファリング、UTF8 エンコーディングjava.io.PrintWriters
包まれたjava.lang.System.out
そしてjava.lang.System.err
) そしてstdin
(UTF8デコードjava.io.BufferedReader
包まれたjava.lang.System.in
) - 機能
print
,println
,putStr
,putChar
に書きますstdout
getChar
そしてgetLine
から読むstdin
ファイルの終わりで例外をスローします。- 以下のような Java クラスに相当する Frege
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
Frege はまだ非常に新しいため、リストやモナドなどの最も基本的な領域ではすでに進歩しているにもかかわらず、ライブラリのサポートがまだ不足していることは明らかです。
さらに、特に IO システムや一般に低レベルのシステム関連トピックにおいて、Haskell との高度な互換性を持たせることが目的ですが、次のような緊張があります。むしろ Java のやり方を採用するべきでしょうか、それとも Haskell のやり方をエミュレートすることを本当に試みるべきでしょうか (これは、標準 C/POSIX ライブラリで利用可能なものに明らかに影響を受けます)。
いずれにせよ、残念なことに、IO に関するものはおそらく Frege ライブラリの中で最も開発が遅れている領域です。これは、綿密なライブラリを開発するのに時間を費やすことなく、その場限りの方法で必要となる少数の Java メソッドのネイティブ関数宣言をすばやく作成することが比較的簡単だからでもあります。
また、Read クラスは今のところ存在しません。この問題が修正されるまでの代替として、String 型にはすべての数値型を解析する関数があります (Java parseXXX() メソッドに基づく)。
(サイドノート:私の 1 日は 24 時間しかなく、家族、犬、そして大事な仕事があるので、Frege システムの改善に協力してくれる貢献者が増えてくれるととても嬉しいです。)
コードに関して:はい、すべての文字ベースの I/O を Reader および Writer インターフェイスを通じて実行するのが正しいと思います。あなたの例は、標準入力リーダーを取得するための便利な関数が必要であることも示しています。標準出力ライターでも同様です。
ただし、複数行を読み取る必要がある場合は、必ず main 関数でリーダーを作成し、それを入力処理アクションに渡します。