Sameh K. Mohamed
Sameh K. Mohamed

Reputation: 2333

Haskell IO function for various data types

I know almost nothing about and I'm reading lots of tutorials and code samples to understand Haskell's IO, but it is still not clear to me.

All examples are like:

main = do  
    putStrLn "Hello, what's your name?"  
    name <- getLine  
    putStrLn ("Hey " ++ name ++ ", welcome !") 

They read a string from IO and there are many other examples that do some customization on input that I don't understand.

My question is simply: How to read Int, Float, Double or Char like using scanf in C with a format string?

And can anyone help me with a clear explanation to IO customization or tricks?

Hint: if the code comes with a main function that would be great - it would make testing easier.

I have very good coding experience in C, C++, Java, C#, Matlab and PHP.

Upvotes: 2

Views: 1402

Answers (3)

ljedrz
ljedrz

Reputation: 22173

isturdy's answer is valid, but in case you want something a bit simpler, the easiest approach is to do it step-by-step:

main = do
    i' <- getLine -- some integral input; it will be received as a String
    d' <- getLine -- some floating input; also will be received as a String
    let i = read i' :: Int -- i is an Int now
        d = read d' :: Double -- d is a Double now
    putStr "" -- so that GHC doesn't complain

The type of getLine is IO String - it reads input as a String. You can then change the type of this string with read (and indicating what type you want). As for a scanf-like experience, you can try something like this:

main = do
    inp <- getLine -- the input is an Int, a String and a Double, like: 4 derp 2.7
    let list = words inp -- divide the input String into a list of Strings
        val = read (list !! 0) :: Int -- val equals 4, its type is Int
        str = list !! 1 -- str is a String ("derp"), no additional action required
        dbl = read (list !! 2) :: Double -- dbl equals 2.7 and is a Double
    putStr ""

Upvotes: 3

permeakra
permeakra

Reputation: 622

You should dig into Read typeclass. It is a standard typecalss for values that can be read from string and very useful in controlled environment when there is no need for error reporting. If you wish to read your own datatype, you probably have to use deriving Read statement.

However, if one want to read arbitrary input, it is standard to use parsec library. Parsec is parser combinator library with several predefined basic parsers. An extra package provides many parsers for numbers. Special hi-speed parser combinator libraries and parser generator also exist.

Upvotes: 1

isturdy
isturdy

Reputation: 1231

The most direct way is to use read (you will often have to provide an explicit type), as in

main = do  
    putStrLn "Hello, what's your age?"  
    age <- liftM read getLine :: IO Int
    putStrLn ("Hey " ++ (show age)  ++ ", welcome !")

This works well if you know that the string contains just the single value (it throws an exception if it cannot parse the string as the desired datatype). For more complex parsing, I usually jump straight to the Parsec parser combinator library (which is probably all the parser you will ever need in Haskell, but also handles simple jobs with minimal overhead). If that does not suit you a quick search of Hackage reveals some candidate libraries offering a simpler scanf-like function: see, among others, Text.XFormat.Read and Text.PrintScan, although I cannot personally vouch for either.

Upvotes: 4

Related Questions