How to do something with data from stdin, line by line, the maximum number of times and print the number of lines in Haskell

This code reads the number of lines to process from the first line of stdin, then it executes a num_of_lines_to_process loop, doing some calculations and prints the result. I want him to print the line number in the line "#" after "#", but I don’t know how to get it.

import IO import Control.Monad (replicateM) main :: IO () main = do hSetBuffering stdin LineBuffering s <- getLine let number_of_lines_to_process = read s :: Integer lines <- replicateM (fromIntegral(number_of_lines_to_process)) $ do line <- getLine let number = read line :: Integer result = number*2 --example putStrLn ("Line #"++": "++(show result)) --I want to print the number of the iteration and the result return () 

I assume the solution to this problem is very simple, but I am not familiar with Haskell (coding in it for the first time), and I have not found any way to do this. Can anyone help?

+6
source share
5 answers

You can use forM_ instead of replicateM :

 import IO import Control.Monad main :: IO () main = do hSetBuffering stdin LineBuffering s <- getLine let number_of_lines_to_process = read s :: Integer forM_ [1..number_of_lines_to_process] (\i -> do line <- getLine let number = read line :: Integer result = number * 2 putStrLn $ "Line #" ++ show i ++ ": " ++ show result) 

Note that since you use forM_ (which discards the results of each iteration), you do not need an additional return () at the end - the do block returns the value of the last statement, which in this case is () , which returns forM_ .

+13
source

The trick is to first create a list of all the line numbers you want to print, and then skip this list by printing each number in turn. So, like this:

 import Control.Monad import System.IO main :: IO () main = do hSetBuffering stdin LineBuffering s <- getLine let lineCount = read s :: Int -- Create a list of the line numbers lineNumbers = [1..lineCount] -- `forM_` is like a "for-loop"; it takes each element in a list and performs -- an action function that takes the element as a parameter forM_ lineNumbers $ \ lineNumber -> do line <- getLine let number = read line :: Integer result = number*2 --example putStrLn $ "Line #" ++ show lineNumber ++ ": " ++ show result return () 

Read the definition of forM_ .

By the way, I would not recommend using the old IOS Haskell98 library. Use System.IO instead.

+9
source

You can calculate the results, list them and then print:

 import IO import Control.Monad (replicateM) -- I'm assuming you start counting from zero enumerate xs = zip [0..] xs main :: IO () main = do hSetBuffering stdin LineBuffering s <- getLine let number_of_lines_to_process = read s :: Integer lines <- replicateM (fromIntegral(number_of_lines_to_process)) $ do line <- getLine let number = read line :: Integer result = number*2 --example return result mapM_ putStrLn [ "Line "++show i++": "++show l | (i,l) <- enumerate lines ] 
+5
source

I am still new to Haskell, so there may be problems with the program below (it works). This program is a tail recursive implementation. The doLine helper function carries the line number. The processing step is taken into account in the process , which you can change in accordance with the problem you have set.

 import System.IO import Text.Printf main = do hSetBuffering stdin LineBuffering s <- getLine let number_of_lines_to_process = read s :: Integer processLines number_of_lines_to_process return () -- This reads "max" lines from stdin, processing each line and -- printing the result. processLines :: Integer -> IO () processLines max = doLine 0 where doLine i | i == max = return () | otherwise = do line <- getLine let result = process line Text.Printf.printf "Line #%d: %d\n" (i + 1) result doLine (i + 1) -- Just an example. (This doubles the input.) process :: [Char] -> Integer process line = let number = read line :: Integer in number * 2 

I am a new hackell, so any criticism from this is welcome.

+2
source

As an alternative, I thought you might like the answer with minimal removal of the monad and no do . We write a lazy list of user data with an endless list of line numbers, using an enumeration function to provide us with the desired result.

 import System.IO import Control.Monad (liftM) --Here the function that does what you really want with the data example = (* 2) --Enumerate takes a function, a line number, and a line of input and returns --an ennumerated line number of the function performed on the data enumerate :: (Show a, Show b, Read a) => (a->b) -> Integer -> String -> String enumerate fix = "Line #" ++ show i ++ ": " ++ (show . f . read $ x) -- show . f . read handles our string conversion -- Runover takes a list of lines and runs -- an enumerated version of the sample over those lines. -- The first line is the number of lines to process. runOver :: [String] -> [String] runOver (line:lines) = take (read line) $ --We only want to process the number of lines given in the first line zipWith (enumerate example) [1..] lines -- run the enumerated example -- over the list of numbers and the list of lines -- In our main, we'll use liftM to lift our functions into the IO Monad main = liftM (runOver . lines) getContents 
0
source

Source: https://habr.com/ru/post/914510/


All Articles