I'm trying to read n lines of content into a List of Strings. I've tried several variations of the code below, but nothing worked.
main = do
input <- getLine
inputs <- mapM getLine [1..read input]
print $ length input
This throws the following error:
Couldn't match expected type `a0 -> IO b0'
with actual type `IO String'
In the first argument of `mapM', namely `getLine'
In a stmt of a 'do' block: inputs <- mapM getLine [1 .. read input]
In the expression:
do { input <- getLine;
inputs <- mapM getLine [1 .. read input];
print $ length input }
And
main = do
input <- getLine
let inputs = map getLine [1..read input]
print $ length input
throws
Couldn't match expected type `a0 -> b0'
with actual type `IO String'
In the first argument of `map', namely `getLine'
In the expression: map getLine [1 .. read input]
In an equation for `inputs': inputs = map getLine [1 .. read input]
How can I do this?
Use replicateM from Control.Monad:
main = do
input <- getLine
inputs <- replicateM (read input) getLine
print $ length inputs
In the spirit of give a man a fish / teach a man to fish: You could have found this yourself by searching Hoogle.
You have:
an action to perform of type IO String
a number of times to perform that action (type Int)
You want:
an action of type IO [String]
So you could search Hoogle for (IO String) -> Int -> (IO [String]). replicateM is the first hit.
One other way you can do this action is by using the pure replicate and the sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)
tool. Lets say first we will ask for a count and then ask for that many integers to print their sum on the terminal.
sumCountManyData :: IO ()
sumCountManyData = putStr "How many integers to sum..? "
>> getLine
>>= sequence . flip replicate getLine . read
>>= print . sum . map read
Related
I want a program that takes lines and prints reverse when it encounters an empty line.
This is my code.
back :: IO()
back = do
line <- getLine
if (not $ null line) then do
mapM_ putStrLn (reverse line)
else return()
When I try to run this it gives an error.
* Couldn't match type `Char' with `[Char]'
Expected: [String]
Actual: [Char]
* In the second argument of `mapM_', namely `(reverse line)'
In a stmt of a 'do' block: mapM_ putStrLn (reverse line)
In the expression: do mapM_ putStrLn (reverse line)
|
6 | mapM_ putStrLn(reverse line)
| ^^^^^^^^^^^^
What is going wrong here?
line is a String. Since you use mapM_ putStrLn, it expects a list of strings, so mapM_ putStrLn :: [String] -> IO ().
It is not entirely clear if you want to reverse each line, or the lines itself. In case of the former, you can work with:
back :: IO()
back = do
line <- getLine
if not (null line) then do
putStrLn (reverse line)
back
else return()
in case of the latter, you can use recursion, and first call back recursively, and then print the line:
back :: IO()
back = do
line <- getLine
if not (null line) then do
back
putStrLn line
else return()
Assume i have something like this
main = do
input_line <- getLine
let n = read input_line :: Int
replicateM n $ do
input_line <- getLine
let x = read input_line :: Int
return ()
***putStrLn $ show -- Can i access my replicateM here?
return ()
Can i access the result of my replicateM such as if it was a returned value, and for example print it out. Or do i have to work with the replicateM inside the actual do-block?
Specialized to IO
replicateM :: Int -> IO a -> IO [a]
which means that it returns a list. So in your example you could do:
results <- replicateM n $ do
input_line <- getLine
let x = read input_line :: Int
return x -- <- we have to return it if we want to access it
print results
replicateM n a returns a list of the values returned by a. In your case that'd just be a list of units because you have the return () at the end, but if you replace that with return x, you'll get a list of the read integers. You can then just use <- to get it out of the IO.
You can also simplify your code by using readLine instead of getLine and read. Similarly putStrLn . show can be replaced with print.
main = do
n <- readLn
ints <- replicateM n readLn :: IO [Int]
print ints
Of course. Its type is replicateM :: Monad m => Int -> m a -> m [a]. It means it can appear to the right of <- in a do block:
do
....
xs <- replicateM n $ do { ... }
....
xs will be of type [a], as usual for binding the results from Monad m => m [a].
With your code though, where you show return () in that nested do, you'll get ()s replicated n times in your xs. Presumably in the real code you will return something useful there.
When in ghci mode I can type this line :
map read $ words "1 2 3 4 5" :: [Int]
and get
[1,2,3,4,5]
When I make a file named splitscan.hs containing this line:
map read $ words scan :: [Float]
I get this error:
[1 of 1] Compiling Main ( splitscan.hs, splitscan.o )
splitscan.hs:1:1: error:
Invalid type signature: map read $ words str :: ...
Should be of form <variable> :: <type>
|
1 | map read $ words str :: [Float]
| ^^^^^^^^^^^^^^^^^^^^
When I do this:
import System.IO
main = do
scan <- readFile "g924310_b1_copy.txt"
map read $ words scan :: [Float]
putStr scan
I get :
readscan.hs:5:5: error:
• Couldn't match type ‘[]’ with ‘IO’
Expected type: IO Float
Actual type: [Float]
• In a stmt of a 'do' block: map read $ words scan :: [Float]
In the expression:
do scan <- readFile "g924310_b1_copy.txt"
map read $ words scan :: [Float]
putStr scan
In an equation for ‘main’:
main
= do scan <- readFile "g924310_b1_copy.txt"
map read $ words scan :: [Float]
putStr scan
The question is, how do implement the ghci line such that I can get all the words from the scan and make a list of them that I can later fit regressions, add constants to etc.
In Haskell, variables are immutable. So map read $ words scan doesn't change the variable scan; it returns a new value. You need to use this new value if you want to do something with it.
import System.IO
main = do
scan <- readFile "g924310_b1_copy.txt"
let scan' = map read $ words scan :: [Float]
print scan'
I would do the following:
floats :: String -> [Float]
floats = fmap read . words
main :: IO ()
main = print =<< fmap floats readFile "g924310_b1_copy.txt"
I have a problem with a Haskell script. I'm trying to learn Haskell through doing problems I find online. The input I get is:
Int -> Number of test cases
S1 -> String 1 for each test case
S2 -> String 2 for each test case
Each S1 and S2 is a space delimited string of numbers. I convert them to a list of Ints with the function strToIntList. I then want to process the two lists and return an integer value based on the results. I get the following error: Couldn't match type 'IO Integer' with 'Int' on line 24 and I stared for ages but just can't figure out why (full error at end of post).
If someone could explain why I'm going wrong, I would be very grateful.
This is my script:
import Data.List
import Data.List.Split
main = do
cases <- readLn
doLoop cases
toInt x = read x :: Int
strToIntList s = [read x :: Int | x <- (splitOn " " s)]
minOfTwo :: Int
minOfTwo = do
sa <- getLine
sb <- getLine
return $ minimum [1..50]
-- return $ minimum $ strToIntList sa
doLoop 0 = return ()
doLoop loopIndex = do
q <- getLine
let c = minOfTwo
print(c)
doLoop (loopIndex-1)
This is the full error I'm getting:
Couldn't match type `IO Integer' with `Int'
Expected type: IO String -> (String -> IO Integer) -> Int
Actual type: IO String -> (String -> IO Integer) -> IO Integer
In a stmt of a 'do' block: sa <- getLine
In the expression:
do { sa <- getLine;
sb <- getLine;
return $ minimum [1 .. 50] }
In an equation for `minOfTwo':
minOfTwo
= do { sa <- getLine;
sb <- getLine;
return $ minimum [1 .. 50] }
The getLine function is in the IO monad, and therefore any function that calls getLine must also be in the IO monad. Change your type signature for minOfTwo from Int to IO Int, and that particular problem will go away.
(You'll also need to change let c = minOfTwo into c <- minOfTwo.)
There may be other errors, but this is the one causing your error message.
Basically I would like to find a way so that a user can enter the number of test cases and then input their test cases. The program can then run those test cases and print out the results in the order that the test cases appear.
So basically I have main which reads in the number of test cases and inputs it into a function that will read from IO that many times. It looks like this:
main = getLine >>= \tst -> w (read :: String -> Int) tst [[]]
This is the method signature of w: w :: Int -> [[Int]]-> IO ()
So my plan is to read in the number of test cases and have w run a function which takes in each test case and store the result into the [[]] variable. So each list in the list will be an output. w will just run recursively until it reaches 0 and print out each list on a separate line. I'd like to know if there is a better way of doing this since I have to pass in an empty list into w, which seems extraneous.
As #bheklilr mentioned you can't update a value like [[]]. The standard functional approach is to pass an accumulator through a a set of recursive calls. In the following example the acc parameter to the loop function is this accumulator - it consists of all of the output collected so far. At the end of the loop we return it.
myTest :: Int -> [String]
myTest n = [ "output line " ++ show k ++ " for n = " ++ show n | k <- [1..n] ]
main = do
putStr "Enter number of test cases: "
ntests <- fmap read getLine :: IO Int
let loop k acc | k > ntests = return $ reverse acc
loop k acc = do
-- we're on the kth-iteration
putStr $ "Enter parameter for test case " ++ show k ++ ": "
a <- fmap read getLine :: IO Int
let output = myTest a -- run the test
loop (k+1) (output:acc)
allOutput <- loop 1 []
print allOutput
As you get more comfortable with this kind of pattern you'll recognize it as a fold (indeed a monadic fold since we're doing IO) and you can implement it with foldM.
Update: To help explain how fmap works, here are equivalent expressions written without using fmap:
With fmap: Without fmap:
n <- fmap read getLine :: IO [Int] line <- getLine
let n = read line :: Int
vals <- fmap (map read . words) getLine line <- getLine
:: IO [Int] let vals = (map read . words) line :: [Int]
Using fmap allows us to eliminate the intermediate variable line which we never reference again anyway. We still need to provide a type signature so read knows what to do.
The idiomatic way is to use replicateM:
runAllTests :: [[Int]] -> IO ()
runAllTests = {- ... -}
main = do
numTests <- readLn
tests <- replicateM numTests readLn
runAllTests tests
-- or:
-- main = readLn >>= flip replicateM readLn >>= runAllTests