user2878641
user2878641

Reputation:

Reading int's in Haskell

I've been studying Haskell, more specifically the IO monad, and I would like to know how can i do the following:

Let's say I have this function signature:

getNumber :: String −> (Int −> Bool) −> IO Int  

and this text:

"My name is Gary, and I'm 21 years old"

If I want to read only the number "21" from this sentence, how would I do it in Haskell ?

Upvotes: 0

Views: 214

Answers (2)

Yitz
Yitz

Reputation: 5117

Here is a function that extracts multiple readable things from a String:

import Data.List (unfoldr, tails)
import Data.Maybe (listToMaybe)

readMany :: Read a => String -> [a]
readMany = unfoldr $ listToMaybe . concatMap reads . tails

So for example:

> readMany "I like the numbers 7, 11, and 42." :: [Int]
[7,11,42]

You can easily specialize this to jozefg's function getNumber:

justOne :: [a] -> Maybe a
justOne [x] = Just x
justOne _   = Nothing

getNumber :: String -> Maybe Int
getNumber = justOne . readMany

Or you can be a little more lenient and pick the first number when more than one is specified:

getNumber = listToMaybe . readMany

Upvotes: 1

daniel gratzer
daniel gratzer

Reputation: 53901

This can be done with list processing operations,

import Text.Read
import Data.Char

getNumber :: String -> Maybe Int
getNumber = readMaybe . takeWhile isDigit . dropWhile (not . isDigit)

Now it's much easier to use this to build your function. It's not clear what the Int -> Bool is for, or, if you already have the string, why you need IO. To get your function you could do something like

yourFunc :: (Int -> Bool) -> IO Int
yourFunc f = do
   r <- fmap getNumber getLine
   case r of
     Nothing -> putStrLn "Please enter a number" >> yourFunc f
     Just x | f x       -> return x
            | otherwise -> putStrLn "Doesn't satisfy predicate" >> yourFunc f

Usage:

> yourFunc even
  I am a person
  Please enter a number
  I am 21
  Doesn't satisfy predicate
  I am 22
  22

However if you want to do any serious parsing, I'd recommend Parsec or Attoparsec, they're both quite easy to use and much more robust.

Upvotes: 1

Related Questions