I have file txt which contain two numbers, for example:
2.
3.
How can you see, each end of line is ended with dot.
How can I read it and print for example sum of this numbers?
If my file don't contain dots, so for example I have
2
3
it isn't problem. My code is:
main3 = do
x <- openFile "C:/Users/file.txt" ReadMode
m <- hGetLine x
n <- hGetLine x
return ((read m::Int)+(read n::Int))
and it work good. But when in my file are dots, i don't know what can I do. Maybe are any library?
Thank's for help.
The trouble is that read won't parse "3." to mean 3. If you just want to do this in a hacky way, you can drop the last character.
main4 = do
x <- openFile "C:/Users/file.txt" ReadMode
m <- hGetLine x
n <- hGetLine x
return ((read (init m)::Int)+(read (init n)::Int))
which may work but is quite fragile since it assumes that the only non-digit character in each line is the last. We can do a little better by assuming the first n digit characters form our numbers
import Data.Char
-- takeWhile isDigit :: String -> String
main5 path = do
f <- readFile path
numberStrings <- map (takeWhile isDigit) (lines f)
sum (map read numberStrings)
The most robust solution would be to upgrade to a "parser combinator library" like Parsec which would let you write out the grammar of your text file.
There are a few ways to do it.. The simplest being
main = do
text <- readFile "file.txt" -- Grab the file
let nums = map read . map init . lines $ text
print $ sum nums
init just drops the .. However I'd write it like this
import Text.Parsec.String
import Text.Parsec
import Control.Applicative ((<*), (<$>))
getNums :: Parser [Int]
getNums = num `sepEndBy` newline
where num = read <$> many1 digit <* char '.'
main = parseFromFile getNums "filename" >>= print . fmap sum
Is it worth using parsec for something like this? The answer is "it depends". My rule of thumb is that if I'm planning to use it more than once, then just bite the bullet and use parsec. It's much, much easier to modify something that uses a library like parsec for new and more complex formats. Plus you get free [decent] error messages this way.
You can to this in several steps, exploiting Haskell's monadic API:
Read in the file line per line
Check whether each line is ended with a dot: Use map and return a Maybe monad: Nothing when the line is not ended with a dot, Just (value without dot) when the line ended with a dot
Use map + flatten to convert each String to a number, again with the Maybe monad. Nothing when there is an error, or Just x to contain the number
Sum the values using fold
When I have some time, I will try to build an example. It's always fun to play with Haskell's monadic API.
Related
I am new to Haskell and I am trying to apply a function (gcd) to input on standard in, which is line separated and each line contains no less or more than two numbers. Here is an example of my input:
3
10 4
1 100
288 240
I am currently breaking up each line into a tuple of both numbers, but I am having trouble figuring out how to separate these tuples and apply a function to them. Here is what I have so far:
import Data.List
main :: IO ()
main = do
n <- readLn :: IO Int
content <- getContents
let
points = map (\[x, y] -> (x, y)). map (map (read::String->Int)). map words. lines $ content
ans = gcd (fst points :: Int) (snd points :: Int)
print ans
Any information as two a good place to start looking for this answer would be much appreciated. I have read through the Learning Haskell tutorial and have not found any information of this particular problem.
You are pretty close. There is no reason to convert to a tuple or list of tuples before calling gcd.
main = do
contents <- getContents
print $ map ((\[x,y] -> gcd (read x) (read y)) . words) . lines $ contents
All the interesting stuff is between print and contents. lines will split the contents into lines. map (...) applies the function to each line. words splits the line into words. \[x,y] -> gcd (read x) (read y) will match on a list of two strings (and throw an error otherwise - not good practice in general but fine for a simple program like this), read those strings as Integers and compute their GCD.
If you want to make use of lazy IO, in order to print each result after you enter each line, you can change it as follows.
main = do
contents <- getContents
mapM_ (print . (\[x,y] -> gcd (read x) (read y)) . words) . lines $ contents
Or, you can do it in a more imperative style:
import Control.Monad
main = do
n <- readLn
replicateM_ n $ do
[x, y] <- (map read . words) `liftM` getLine
print $ gcd x y
Im trying to write a simple function to learn the IO monad in Haskell. The function is supposed to take the sum of some given integers from the console but when the function has run for example 4 times it says "1*** Exception: Char.digitToInt: not a digit '\n'"
import Data.Char
readInts :: IO ()
readInts = do
putStrLn "Choose nr of ints to sum."
c <- getChar
let i = digitToInt c
-- code.
let sum = getInts i
let str = "\nSum is: " ++ [intToDigit i].
putStrLn str
getInt :: IO Int
getInt = do
c <- getChar
return (digitToInt c)
getInts :: Int -> IO Int
getInts n = if n == 0
then return 0
else
do i <- getInt
j <- getInts
return (i+j)
Can somebody please explain where my recursion is going wrong?
You're simply using the wrong tools to convert between "keyboard data" and numbers. Has little to do with IO.
intTodigit, as the name says, acts on single digits / characters, not on general numbers. What you want is to read / print entire strings, which can handle multi-digit numbers. Replace getChar with getLine, digitToInt with read, and [intToDigit i] with show i. Then it should work fine.
However, it would be better to make some more simplifications.
getInt basically exists already, though in more general form: readLn gets a line from stdin and inteprets it as the required type.
getInts is implemented more complicately than necessary. Explicit recursion over a counting variable (BTW, it has to be getInts (n-1) in the recursion) is ugly; such looping is obviously so common that there exists a standard solution (you need to import Control.Monad) for it which looks alot like loops in imperative languages you might be used to:
getIntsAndSum :: Int -> IO Int
getIntsAndSum n = fmap sum . forM [1 .. n] $ \k -> do
i <- getInt
return i
which can in fact be further simplified to
fmap sum . forM [1 .. n] $ \_ -> getInt
because do blocks a just an optional construct to help you chain actions, but when there's only one action you can simply write that on its own.
Ideally, you would not have to first ask for the number of numbers at all: just gather all numbers you're given, and sum them up. This works, as jamshidh said, very simply with interact.
main = interact processInput
where processInput allInput = show (sum allNumbers)
where allNumbers = map read . lines allInput
and that's it! Nothing else needed. In fact, this can be written yet simpler: you basically have just one simple data-flow pipeline.
main = interact $ show . sum . map read . lines
getChar gets every char, including any "\n" that you type in (which you need to submit the answer). Try filtering these out.
A better way to solve this could be to use "interact" to get the user input, and break apart the data using lines. That way the user could input multi digit numbers, and the "\n"'s would be removed.
The following sums numbers entered at the command line (without any prompting, end inputting by typing ^d).
main = interact (show . sum . fmap read . lines)
I keep getting an error: couldn't match expected type 'Bool' with actual type '[t0]'. I'm trying to get user inputs of string and then output however many strings in reversed ORDER.
Example input:
HI1
HI2
Example output:
HI2
HI1
My code:
Back :: Int -> IO()
Back x = do line <- sequence_[getLine|[1..x]]
mapM_ print (reverse line)
To expand on Vitus's comment, import Control.Monad, then
back count = do
lines <- replicateM count getLine
mapM_ putStrLn (reverse lines)
If this doesn't work for you, please say what error message you get, or give an example of incorrect output.
In this case, we can forego do notation fairly easily:
back count = mapM_ putStrLn . reverse =<< replicateM count getLine
Or
back count = mapM_ putStrLn =<< liftM reverse (replicateM count getLine)
You may or may not find either of those to be clearer.
Note that your function name must start with a lower case letter, e.g. back. Back as a function name is a syntax error.
Also note that indentation is significant. The indentation of the do block in your question is wrong; the do blocks in my and melpomene's answers are correctly indented.
back :: Int -> IO ()
back x = do line <- sequence [getLine | _ <- [1 .. x]]
mapM_ putStrLn (reverse line)
I'm trying to create a function which allows the user to input a list of strings. The function takes the length and allows the user to input length-1 more lines. Then each line is checked to ensure it is the same length as the original line. However, I'm having a few problems and that I can't find a solution to.
The problems are that I can input more than count-1 lines and the length isn't being calculated as I expected.. for example if I input ["12","13"] and then ["121","13"] the error is given, although they are the same length!
read :: IO [Line]
read = do
line <- getLine
let count = length line
lines <- replicateM (count-1) $ do
line <- getLine
if length line /= count
then fail "too long or too short"
else return line
return $ line : lines
Line is of type String.
readLn gives a parse error.
It sounds to me like you're getting confused about the difference between getting a line as a String and reading/parsing a line of input as a custom type. You are using getLine, which always returns exactly the String that the user types. Compare:
Prelude> fmap length getLine
["12","13"]
11
Prelude> length "[\"12\",\"13\"]" -- explanation of the 11
11
Prelude> fmap length (readLn :: IO [String])
["12","13"]
2
Prelude> length ["12", "13"] -- explanation of the 2
2
As demonstrated here, you probably want to use readLn, which first gets a line of input and then parses it with read.
-- defined in the Prelude
readLn = do
s <- getLine
return (read s)
If I modify your code to include the imports and definitions below:
import Control.Monad
type Line = [String]
...and to call readLn instead of getLine, then I can type the literal lines ["12","13"] and ["121","13"] without errors.
So im educating myself for the future
firstLetter :: IO String
firstLetter = do
x <- getChar
if (x == ' ')
then return (show x)
else firstLetter
So it would get lines until the first line, that starts with empty char
how can I do it, so if empty line comes, it returns all head(x)
for example:
Liquid
Osone
Liquid
(empty line)
returns
"LOL"
Try this. The library function lines will split the input into lines for you, so all that is left is extracting the first character from each string in a list until one string is empty. An empty string is just a null list, so you can check for that to end the recursion over the list of strings.
firstLetters :: [String] -> String
firstLetters (x:xs)
| null x = []
| otherwise = head x : firstLetters xs
main = do
contents <- getContents
putStrLn . firstLetters . lines $ contents
Have you seen interact? This'll help you eliminate the IO and that always seems to make thing simpler for me and hopefully you too.
That reduces it to a problem that reads a string and returns a string.
Here's a rough go at it. getLines takes a string, breaks it into lines and consumes them (takeWhile) until it meets a line containing a single space (I wasn't sure on your ending condition, as the other poster says using null will stop at the first empty list). Then it goes over those lines and gets the first character of each (with map head).
getLines :: String -> String
getLines = map head . takeWhile (/= " ") . lines
main :: IO ()
main = interact getLines