Haskell Prelude.read: no parse String - haskell

from haskell examples http://learnyouahaskell.com/types-and-typeclasses
ghci> read "5" :: Int
5
ghci> read "5" :: Float
5.0
ghci> (read "5" :: Float) * 4
20.0
ghci> read "[1,2,3,4]" :: [Int]
[1,2,3,4]
ghci> read "(3, 'a')" :: (Int, Char)
(3, 'a')
but when I try
read "asdf" :: String
or
read "asdf" :: [Char]
I get exception
Prelude.read No Parse
What am I doing wrong here?

This is because the string representation you have is not the string representation of a String, it needs quotes embedded in the string itself:
> read "\"asdf\"" :: String
"asdf"
This is so that read . show === id for String:
> show "asdf"
"\"asdf\""
> read $ show "asdf" :: String
"asdf"
As a side note, it's always a good idea to instead use the readMaybe function from Text.Read:
> :t readMaybe
readMaybe :: Read a => String -> Maybe a
> readMaybe "asdf" :: Maybe String
Nothing
> readMaybe "\"asdf\"" :: Maybe String
Just "asdf"
This avoids the (in my opinion) broken read function which raises an exception on parse failure.

Related

Exception Handling in Haskell no parse

So I have a file where the first line has the format ([String], [(Int, Int)], [(Int, Int)], Int) and the rest of the lines have the format [((Int, Int), (Int, Int), String)]. I managed to get the the input and parse it with the following function:
someFunction :: String -> IO (String)
someFunction fileName = do
handle <- openFile fileName ReadMode
contents <- hGetLine handle
let firstLine = read contents :: ([String], [(Int, Int)], [(Int, Int)], Int)
restOfLines <- map read <$> lines <$> hGetContents handle :: IO [((Int, Int), (Int, Int), String)]
...
The thing is, that I want to print a custom error if the file has the wrong format. So if something is missing or what not, it should only print "some error". Otherwise, the lines have to be parsed so I can do some other things with the content. I would appreciate it if someone could help me with this.
The simplest way to detect whether a Read parser failed is to use readMaybe. E.g. in GHCi:
> import Text.Read (readMaybe)
> :t readMaybe
readMaybe :: Read a => String -> Maybe a -- Defined in ‘Text.Read’
> readMaybe "1" :: Maybe Int
Just 1
> readMaybe ":(" :: Maybe Int
Nothing
You can pattern-match on the result of readMaybe with case like any other use of Maybe:
case readMaybe input of
Just parsed -> … -- Use parsed value
Nothing -> … -- Report error
This can only report a generic failure; for more complex parsing and validation, you should use a proper parsing library. One included with base is Text.ParserCombinators.ReadP:
import Control.Applicative (some)
import Data.Char (isDigit)
import Text.ParserCombinators.ReadP (ReadP)
import qualified Text.ParserCombinators.ReadP as ReadP
-- Parse one or more digits.
number :: ReadP Int
number = read <$> some (ReadP.satisfy isDigit)
These parsers can be executed on some input with readP_to_S; by default they enumerate all possible parses, which you can constrain with functions like eof (require complete input) or <++ (biased choice).
> import Text.ParserCombinators.ReadP (readP_to_S)
> readP_to_S number "123"
[(1,"23"),(12,"3"),(123,"")]
> readP_to_S (number <* ReadP.eof) "123"
[(123,"")]
You can pattern-match on the resulting list to validate, for example, that there’s only one result and extract what you want or report the error. Another popular choice of parsing library is the megaparsec package, which can additionally provide nice custom error messages with source locations.

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

Is there an alternative to `read` that returns Maybe?

I'm trying to get a number from IO like this:
numberString <- getLine
print 3 + read numberString
This works if numberString is a good string of number (like "3241"), but when it's not something that good (like "124gjh"), it throws an exception:
*** Exception: Prelude.read: no parse
There's a reads function which returns a [(a0, String)] and when nothing is matched this would be a []. Is there an easy way that I have something like this:
read' :: String -> Maybe a
so that I just get a Nothing if things doesn't work instead of just stopping abruptly?
There is readMaybe right in Text.Read which should do exactly what you asked for:
Prelude> import Text.Read(readMaybe)
Prelude Text.Read> readMaybe "3241" :: Maybe Int
Just 3241
Prelude Text.Read> readMaybe "Hello" :: Maybe Int
Nothing

Stop program from crashing when entering not-numbers in a menu with numbered options

My search function works properly when the input is a number, but crashes when it is not. What can I add to my code to prevent that from happening?
searchAge = do
putStrLn "\n Please type the age of the person you're looking for: \n"
age <- getLine
input <- readFile $ "databas.txt"
putStrLn "\n Here are all the people that matches your search: \n"
let people = parse input
output = map personToString (filter (\p -> personAge p == read age) people)
in putStrLn (unlines output)
putStrLn "Let's get back to the search menu again!"
searchDatabase
Listen up, oh younger one,
as this is a maddening song.
Take a look and you will see
read :: String -> Int is wrong for ye.
Its type is wrong, its result is unknown;
if been used on a string like "frown".
But here is for the final hint
you're looking for readMaybe :: String -> Maybe Int.
The problem with read is that there is no notion of failure in its type signature:
read :: Read a => String -> a
What happens if we set a to Int and try to use it on the string "frown"? It will result in an exception:
ghci> read "frown" :: Int
*** Exception: Prelude.read: no parse
After all, what should it return? Anything from the domain of Int is a valid value.
Enter readMaybe :: Read a => String -> Maybe a. Now the potential error is covered in the type signature, and it does not result in an exception anymore:
ghci> import Text.Read
ghci> readMaybe "frown" :: Maybe Int
Nothing
ghci> readMaybe "15" :: Maybe Int
Just 15
We can wrap this in a new function called getNumber that repeatedly asks for an Int until the user actually provides one:
getNumber :: IO Int
getNumber = do
line <- getLine
case (readMaybe line :: Maybe Int) of
Just x -> return x
Nothing -> putStrLn "Please enter a number!" >> getNumber
You can then use it to get an Int instead of a String for your age:
searchAge = do
...
age <- getNumber
input <- readFile "databas.txt"
putStrLn "\n Here are all the people that matches your search: \n"
let people = parse input
output = map personToString (filter (\p -> personAge p == age) people)
in putStrLn (unlines output)

Converting Right String to Float

I'm struggling with converting a Right String. I have a method called getEval which evaluates a math expression (a String basically), and I get it back as follows:
*Main> getEval "3+6"
Right "9"
the type of getEval is
*Main> :t getEval "3+6"
getEval "3+6"
:: (Functor m, Control.Monad.CatchIO.MonadCatchIO m) =>
m (Either InterpreterError String)
getEval looks like this:
getEval str = runInterpreter $ setImports ["Prelude"] >> eval str
If it matters, getEval uses the eval in Haskell's hint library (Language.Haskell.Interpreter) to do the actual parsing and calculation.
How can I get this into a float?
getEval str = do
Right res <- Interpreter.runInterpreter (Interpreter.setImports
["Prelude"] >> Interpreter.interpret str (Interpreter.as ::
Float))
return res
case getEval "3+6" of
Right value = read value :: Float
Left errstr = error ("Interpreter error" ++ errstr)
ought to do what you're expecting. You'd probably want to look at readsPrec as well, if you're concerned about Read parsing errors.

Resources