Reputation:
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
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
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