Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Frege's equivalent of Haskell's getLine and read

Is there any Frege's equivalent of Haskell's getLine and read to parse input from the console in the standard library?

Currently I am doing it like this:

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

Update:

Frege has been evolved so now we have getLine in the standard library itself. As for read, we have conversion methods on String. Now the original problem is simply,

main _ = do
  line <- getLine
  println line.atoi

See Ingo's answer below for more details.

like image 281
Marimuthu Madasamy Avatar asked Feb 27 '12 14:02

Marimuthu Madasamy


1 Answers

Update: I/O support in more recent versions of Frege

As of version 3.21.80, we have better I/O support in the standard libraries:

  • The runtime provides stdout and stderr (buffered, UTF8 encoding java.io.PrintWriters wrapped around java.lang.System.out and java.lang.System.err) and stdin (UTF8 decoding java.io.BufferedReader wrapped around java.lang.System.in)
  • Functions print, println, putStr, putChar write to stdout
  • getChar and getLine read from stdin and throw exceptions on end of file.
  • The Frege equivalents for Java classes like PrintWriter, BufferedWriter etc. are defined in module Java.IO, which is automatically imported. With this, more basic functionality is supported. For example, BufferedReader.readLine has a return type of IO (Maybe String) and does signal the end of file by returning Nothing, like its Java counterpart, who returns null in such cases.

Here is a short example program that implements a basic 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

Because Frege is still quite new, the library support is admittedly still lacking, despite the progress that is already done in the most basic areas, like Lists and Monads.

In addition, while the intent is to have a high degree of compatibility to Haskell, especially in the IO system and generally in the low level system related topics, there is a tension: Should we rather go the Java way or should we really try to emulate Haskell's way (which is in turn obviously influenced by what is available in the standard C/POSIX libraries).

Anyway, the IO thing is probably the most underdeveloped area of the Frege library, unfortunately. This is also because it is relatively easy to quickly write native function declarations for a handful of Java methods one would need in an ad hoc manner, instead of taking the time to develop a well though out library.

Also, a Read class does not exist up to now. As a substiutute until this has been fixed, the String type has functions to parse all number types (based on the Java parseXXX() methods).

(Side note: Because my days also have only 24h and I have a family, a dog and a job to care about, I would be very happy to have more contributors that help making the Frege system better.)

Regarding your code: Yes, I feel it is right to do all character based I/O through the Reader and Writer interfaces. Your example shows also that convenience functions for obtaining a standard input reader are needed. The same holds for standard output writer.

However, when you would need to read more than 1 line, I'd definitly create the reader in the main function and pass it to the input processing actions.

like image 164
Ingo Avatar answered Sep 20 '22 04:09

Ingo