How to parse a float number input in Haskell? - haskell

The problem is that I need to input a decimal number, like a float, with right format.
However, I don't know how can I parse the input to ensure it's really a float. If not, I need to putStrLn "ERR". Assume I have the consecutive input.
As example shown below, what condition can I add after IF to exclude the wrong input format, like 1.2.e!##$, which I should give an "ERR" and loop main rather than get an error and exit program immediately.
input <- getLine
if (read input1 :: Float) > 1.0
then do
let result1 = upperbound (read input :: Float)
let result2 = lowerbound (read input :: Float)
print result4
print result3
main
else do
putStrLn"ERR"
main

read is a partial function - it works only on a subset of the input domain. A better example for a partial function is head: it works well on non-empty lists, but will throw an error on an empty list - and you can only handle errors when in the IO monad. Partial functions are useful in some cases, but you should generally avoid using them. So like head, read is an unsafe function - it may fail when the input cannot be parsed.
read has a safe alternative: readMaybe from Text.Read.
readMaybe :: Read a => String -> Maybe a
readMaybe will never fail - if it can't parse a string, it will return Nothing. Handling a Maybe value is a simple task and can be done in several ways (case expressions, Data.Maybe functions, do notation and so on). Here's an example using a case expression:
import Text.Read
...
case (readMaybe input :: Maybe Float) of
Just f | f > 1.0 -> ...
| otherwise -> ...
Nothing -> ...
This article can be helpful in understanding the different ways of error handling in Haskell.

Prelude> let s1 = "1.223"
Prelude> let s2 = "1"
Prelude> let s3 = "1.2.e!##$"
Prelude> read s1 :: Float
1.223
Prelude> read s2 :: Float
1.0
Prelude> read s3 :: Float
*** Exception: Prelude.read: no parse
read throws an exception when it can't parse the string. You need to handle that exception.

Related

Change List of Strings to List of Integer

First of all, sorry for my bad english. I'm not native and try my best :)
Now to the problem: i have a list of Strings and want to convert them to a list of integers. The Problem is, it's not just numbers, basically the String is a List to.
["[1,2,3,4,5,6,7,8]","[8,7,6,5,4,3,2,1]","[1,2,3,4,5,6,7,8]"]
This is the result i get from my code i'll post further down.
Any idea how i can achieve, that the internal list of numbers are list of integers?
I tried like three hours and didn't find a solution.
Every help is appreciatet.
Kind regards
get "/authors/:author" $ do
authorName <- param "author"
directories <- liftIO(listDirectory("data/" ++ authorName))
liftIO(readFiles directories authorName)
html (T.pack (HtmlModule.h1 ("Author: " ++ authorName)))
readFiles :: [String] -> String -> IO ()
readFiles x authorName = do
let y = addPrefix x authorName
content <- mapM readFile y
putStrLn (show content)
Result: ["[1,2,3,4,5,6,7,8]","[8,7,6,5,4,3,2,1]","[1,2,3,4,5,6,7,8]"]
You can read the string into a list of ints:
let nums = map read content :: [[Int]]
You can use read :: Read a => String -> a to convert a string to a type that is a member of the Read typeclass.
Since Int is a member of the Read typeclass, and [a] is a member of the Read typeclass if a is a member of the Read typeclass, we thus can read a list of Ints:
Prelude> read "[1,2,3,4,5,6,7,8]" :: [Int]
[1,2,3,4,5,6,7,8]
We thus can convert a list of Strings with:
content <- mapM ((read :: String -> [Int]) . readFile) y
read will raise an error in case the String can not be converted. You can make use of readMaybe :: Read a => String -> Maybe a to wrap the result in a Just in case parsing was successful, and Nothing in case parsing failed.

How to check type in haskell

I don't know how to check type of variable in haskell, Here i mean , when i read something from console with getLine ,however i expect it to be an interger but user can enter a string also,then i don't want my program to crash. For example if someone inputs a string and i try to convert it to Int then it will crash(exception) so i want to check whether it is convertable or not. How do i do that ? Thanks for any help :)
main1 = do
let g <- getLine
k = g :: Int
if(k :: Int)
then ........
EDIT: Notice you always have a string from getLine - that's the type it returns. If that string contains an ascii representation of a number then great and keep reading.
If you have a string, g, and say g :: Int the compiler will simply so "no, you are wrong, that's a String". You need to perform a translation - parse the string and compute an Int. The most readily available methods are read in the Prelude and readMaybe in Text.Read.
Read will work but throws exceptions on invalid input:
Prelude> read "4742" :: Int
4742
Prelude> read "no" :: Int
*** Exception: Prelude.read: no parse
Prelude> read "191andmore"
*** Exception: Prelude.read: no parse
The maybe variant is exception safe:
Prelude> import Text.Read
Prelude Text.Read> readMaybe "181" :: Maybe Int
Just 181
Prelude Text.Read> readMaybe "no" :: Maybe Int
Nothing
Prelude Text.Read> readMaybe "211andmore" :: Maybe Int
Nothing

Input function of type `:: IO a`

The only "user input" functions I know of in the Prelude return Strings - but often (I'd say more frequently) we want to read numbers or other types.
Is there a function of type :: IO a or similar, for reading a value of arbitrary type? I've searched hoogle for such a function, but either due to it not existing or due to the large number of other functions of similar type, I've not found anything.
It seems useful and simple enough that there must be a built-in. The closest I've come is this:
-- Eg.
get :: Read a => IO a
get = (liftM read) getLine
main = do
x <- get
print $ x + 5
There's readLn:
readLn :: Read a => IO a
Worth noting that readLn calls readIO in order to raise an IO exception instead of undefined.
Prelude> x <- (fmap read getLine) :: IO Integer
asdf
Prelude> x
*** Exception: Prelude.read: no parse
Prelude> x <- (readIO =<< getLine) :: IO Integer
asdf
*** Exception: user error (Prelude.readIO: no parse)

Parsec: grabbing raw source after parsing

I have a strange whim. Suppose I have something like this:
data Statement = StatementType Stuff Source
Now I want to parse such a statement, parse all the stuff, and after that I want to put all characters that I've processed (for this particular statement) into resulting data structure. For some reason.
Is it possible, and if yes, how to accomplish that?
In general this is not possible. parsec does not expect a lot from its stream type, in particular there is no way to efficently split a stream.
But for a concrete stream type (e.g. String, or [a], or ByteString) a hack like this would work:
parseWithSource :: Parsec [c] u a -> Parsec [c] u ([c], a)
parseWithSource p = do
input <- getInput
a <- p
input' <- getInput
return (take (length input - length input') input, a)
This solution relies on function getInput that returns current input. So we can get the input twice: before and after parsing, this gives us exact number of consumed elements, and knowing that we can take these elements from the original input.
Here you can see it in action:
*Main Text.Parsec> parseTest (between (char 'x') (char 'x') (parseWithSource ((read :: String -> Int) `fmap` many1 digit))) "x1234x"
("1234",1234)
But you should also look into attoparsec, as it properly supports this functionality with the match function.

How to properly use the readMaybe function in IO

I started with programming in Haskell about 4 month ago and now I came to the point where I have to deal with the IO system of Haskell.
I already did a lot of IO actions and haven't faced any problems I couldn't solve by myself, but this time I googled for almost two hours for no avail to get some information about the function readMaybe. So I have the following problem set to solve and I already tried a lot of different approaches to solve it but all the time I get the same failure message from my compiler:
No instance for (Read a0) arising from a use of `readMaybe'
The type variable `a0' is ambiguous
I understand what the compiler does want to tell me but I have no idea how to solve this problem. I already tried to add a class constraint, but without success.
So here is my very small and simple program that is just counting how many valid numbers the user has entered. The program is meant to terminate when the user enters an empty line.
This is just a auxiliary function I want to use for my project later on.
countNumbers :: IO Int
countNumbers = do
x <- count 0
return x where
count :: Int -> IO Int
count n = do
line <- getLine
case line of
"" -> do
return n
_ -> case readMaybe line of
Just _ -> do
x <- count (n+1)
return x
Nothing -> do
x <- count n
return x
Unfortunately I couldn't find out a lot of informations about the function readMaybe. The only thing I could find was in the Haskell library Text.Read:
readMaybe :: Read a => String -> Maybe aSource
Parse a string using the Read instance. Succeeds if there is exactly one valid result.
The very weird thing for me is that I have already written such a function that uses the readMaybe function and it worked perfectly ...
This program is just asking the user for a number and keeps asking as long as the user enters a valid number
getLineInt :: IO Int
getLineInt = do
putStrLn "Please enter your guess"
line <- getLine
case readMaybe line of
Just x -> do
return x
Nothing -> do
putStrLn "Invalid number entered"
x <- getLineInt
return x
So far as I can see there are no differences between the usage of the function readMaybe in the two programs and therefore it works in the one but not in the other :)
I would be really thankful for any hints from you!!
This has nothing to do with IO, so maybe you don't understand what the compiler is trying to tell you. There is a type variable a in readMaybe's signature; a has to have a Read instance, but other than that it can be anything. The compiler is telling you that it doesn't have any way to determine what you want a to be.
In getLineInt you don't have this problem, because you are returning the result of readMaybe and the type signature says it should be Int. In countNumbers, you're not using the result of readMaybe, so there's nothing that can be used to determine the correct type. You can fix this by adding an explicit type signature (I picked Int since you're apparently counting numbers):
_ -> case readMaybe line :: Maybe Int of
Finally a word about do notation: it's just syntactic sugar, you don't have to use it all the time. Instead of do return x you can simply write return x, and instead of
x <- getLineInt
return x
you can simply do
getLineInt
That makes things more readable:
getLineInt :: IO Int
getLineInt = do
putStrLn "Please enter your guess"
line <- getLine
case readMaybe line of
Just x -> return x
Nothing -> putStrLn "Invalid number entered" >> getLineInt
Why does this happen?
In your second function, it is clear that readMaybe line is used as String -> Maybe Int, since type inference notices that you use return x and therefore x must be an Int.
In your first function, you don't use the Maybe's value at all, you just want to check whether the read succeeded. However, since you didn't specify the type (neither explicit nor implicit with type inference), the type variable is ambiguous:
_ -> case readMaybe line of
There's an easy fix: annotate the type:
_ -> case readMaybe line :: Maybe Int of
By the way, this is exactly the same behaviour you encounter when you use read in ghci without any type context:
> read "1234"
<interactive>:10:1:
No instance for (Read a0) arising from a use of `read'
The type variable `a0' is ambiguous
As soon as you make the type clear everything is fine:
> read "1234" :: Int
1234
Making things clear
Now that we've seen why the error happens, lets make this program much simpler. First of all, we're going to use a custom readMaybe:
readMaybeInt :: String -> Maybe Int
readMaybeInt = readMaybe
Now how does one count numbers? Numbers are those words, where readMaybeInt doesn't return Nothing:
countNumbers :: String -> Int
countNumbers = length . filter isJust . map readMaybeInt . words
How does one now calculate the numbers in the standard input? We simply take input until one line is completely empty, map countNumbers on all those lines and then sum:
lineNumberCount :: IO Int
lineNumberCount =
getContents >>= return . sum . map countNumbers . takeWhile (/= "") . lines
If you're not used to the bind methods, that's basically
lineNumberCount :: IO Int
lineNumberCount = do
input <- getContents
return . sum . map countNumbers . takeWhile (/= "") . lines $ input
All in all we get the following terse solution:
import Control.Monad (liftM)
import Data.Maybe (isJust)
import Text.Read (readMaybe)
readMaybeInt :: String -> Maybe Int
readMaybeInt = readMaybe
countNumbers :: String -> Int
countNumbers = length . filter isJust . map readMaybeInt . words
lineNumberCount :: IO Int
lineNumberCount =
getContents >>= return . sum . map countNumbers . takeWhile (/= "") . lines
Now there's only one function working in the IO monad, and all functions are basically applications of standard functions. Note that getContents will close the handle to the standard input. If you want to use you're better of using something like
input :: String -> IO [String]
input delim = do
ln <- getLine
if ln == delim then return []
else input delim >>= return . (ln:)
which will extract lines until a line matching delim has been found. Note that you need to change lineNumberCount in this case:
lineNumberCount :: IO Int
lineNumberCount =
input "" >>= return . sum . map countNumbers

Resources