I have a list of strings, and tried this:
ls = [ "banana", "mango", "orange" ]
main = do
map PutStrLn list_of_strings
That didn't work, and I can't understand why.
ghc print-list.hs
print-list.hs:3:0:
Couldn't match expected type `IO t' against inferred type `[IO ()]'
In the expression: main
When checking the type of the function `main'
Any hints? I suppose it has to do with map returning a list and not a value, but I didn't find an easy way to fix this.
Right now the only way I know to print a list of strings is to write a function that will iterate the list, printing each element (print if the list is [a], but print and recurse if it's (a:b)). But it would be much simpler to just use map...
Thanks!
The type of the main function should be IO t (where t is a type variable). The type of map putStrLn ls is [IO ()]. This why you are getting this error message. You can verify this yourself by running the following in ghci:
Prelude> :type map putStrLn ls
map putStrLn ls :: [IO ()]
One solution to the problem is using mapM, which is the "monadic" version of map. Or you can use mapM_ which is the same as mapM but does not collect the returned values from the function. Since you don't care about the return value of putStrLn, it's more appropriate to use mapM_ here. mapM_ has the following type:
mapM_ :: Monad m => (a -> m b) -> [a] -> m ()
Here is how to use it:
ls = [ "banana", "mango", "orange" ]
main = mapM_ putStrLn ls
Ayman's answer makes most sense for this situation. In general, if you have [m ()] and you want m (), then use sequence_, where m can be any monad including IO.
Related
Sorry if I am being silly but I am a beginner in Haskell ans I am trying to make a print a List with putStrLn but i am not sure how to solve the next problem:
And I am trying to made a basic print List in Haskell with the code:
import System.IO
array = map show [1, 2, 3, 4]
main :: IO ()
main = do
map putStrLn array
but the compiler give me:
8 main.hs:7:3: error:
7 • Couldn't match expected type ‘IO ()’ with actual type ‘[IO ()]’
6 • In a stmt of a 'do' block: map putStrLn array
5 In the expression: do map putStrLn array
4 In an equation for ‘main’: main = do map putStrLn array
How I should fix it?
Haskell handles IO quite differently than other languages.
In a language like Java, System.Out.println(3) is a statement which does not evaluate to a value, so you can't even write something like x = System.Out.println(3);.
In a language like Lisp, (print 3) evaluates to 3 and, in the process of evaluation, prints 3. So saying something like (setq x (print 3)) will set the value of x to 3 and also print 3.
In Haskell, putStrLn "3" represents the command to print 3. Thus, saying x = putStrLn "3" does absolutely nothing except assign x to the command putStrLn "3".
Let's look at some types. We have
map :: (a -> b) -> [a] -> [b]
putStrLn :: String -> IO ()
Thus, we should have
map putStrLn :: [String] -> [IO ()]
map putStrLn array :: [IO ()]
In other words, map putStrLn array is a list of "IO actions" which result in a value of type () (basically, this means that executing the actions results in no extra information).
However, in order to write
main :: IO ()
main = map putStrLn array
which is what
main :: IO ()
main = do map putStrLn array
translates to, we need map putStrLn to be of type IO (), NOT of type [IO ()].
If you wish to execute an action for each element of a list, you can use the for_ function, which has type for_ :: (Foldable g, Applicative f) => g a -> (a -> f ()) -> f (). IO is Applicative and [] is Foldable, so in particular for_ :: [String] -> (String -> IO ()) -> IO () is one type that for_ can take. The code looks like
import Data.Foldable (for_)
array :: [String]
array = map show [1, 2, 3, 4]
main :: IO ()
main = for_ array putStrLn
This would be equivalent in an imperative language to
for each x in array do {
putStrLn x;
}
I tried to print map function's list output using putStrLn as,
main = do
let out = "hello\nworld\nbye\nworld\n"
putStrLn $ map ("out: " ++) $ lines out
It throws error as,
Couldn't match type ‘[Char]’ with ‘Char’
I referred some other code and changed the lastline to
mapM_ putStrLn $ map ("out: " ++) $ lines out
It solves the problem, but how does map monad with underscore suffix work in this case?
mapM_ is based on the mapM function, which has the type
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
And mapM_ has the type
mapM_ :: Monad m => (a -> m b) -> [a] -> m ()
With the former, it acts like the normal map over a list, but where each element has an action run with the results aggregated. So for example if you wanted to read multiple files you could use contents <- mapM readFile [filename1, filename2, filename3], and contents would be a list where each element represented the contents of the corresponding file. The mapM_ function does the same thing, but throws away the results. One definition is
mapM_ f list = do
mapM f list
return ()
Every action gets executed, but nothing is returned. This is useful in situations like yours where the result value is useless, namely that () is the only value of type () and therefore no actual decisions can be made from it. If you had mapM putStrLn someListOfStrings then the result of this would have type IO [()], but with mapM_ putStrLn someListOfStrings the [()] is thrown away and just replaced with ().
I'd like to save a huge list A to a textfile. writeFile seems to only save the list at the very end of the calcultaion of A, which crashes because my memory is insufficient to store the whole list.
I have tried this using
writeFile "test.txt" $ show mylistA
Now I have tried saving the elements of the list, as they are calculated using:
[appendFile "test2.txt" (show x)|x<-mylistA]
But it doesn't work because:
No instance for (Show (IO ())) arising from a use of `print' Possible fix: add an instance declaration for (Show (IO ())) In a stmt of an interactive GHCi command: print it
Can you help me fix this, or give me a solution which saves my huge list A to a text file?
Thank you
The problem is that your list has the type [ IO () ] or "A list of IO actions". Since the IO is on the "inside" of out type we can't execute this in the IO monad. What we want instead is IO (). So a list comprehension isn't going to hack it here.
We could use a function to turn [IO ()] -> IO [()] but this case lends itself to a much more concise combinator.
Instead we can use a simple predefined combinator called mapM_. In the Haskell prelude the M means it's monadic and the _ means that it returns m () in our case IO (). Using it is trivial in this case
[appendFile "test2.txt" (show x)|x<-mylistA]
becomes
mapM_ (\x -> appendFile "test2.txt" (show x)) myListA
mapM_ (appendFile "test2.txt" . show) myListA
This will unfold to something like
appendFile "test2.txt" (show firstItem) >>
appendFile "test2.txt" (show secondItem) >>
...
So we don't ever have the whole list in memory.
You can use the function sequence from Control.Monad to take a (lazily generated) list of IO actions and execute them one at a time
>>> import Control.Monad
Now you can do
>>> let myList = [1, 2, 3]
>>> sequence [print x | x <- myList]
1
2
3
[(),(),()]
Note that you get a list of all the return values at the end. If you want to discard the return value, just use sequence_ instead of sequence.
>>> sequence_ [print x | x <- myList]
1
2
3
I just wanted to expand on jozefg's answer by mentioning forM_, the flipped version of mapM_. Using forM_ you get something that looks like a foreach loop:
-- Read this as "for each `x` in `myListA`, do X"
forM_ myListA $ \x -> do
appendFile "test2.txt" (show x)
I am trying to use splitOn function in haskell to split a string based on some delimiters. So the splitOn function returns data of type [[Char]], but the compiler is showing error saying that the expected type is IO a.
The line of code which is failing is:
splitOn "x" "1 2, 3"
Please suggest.
If you've written something like xs <- splitOn "x" line and simply want to bind a name to splitOn "x" line, then you can use let xs = splitOn "x" line. <- is for binding values from IO actions, rather than assigning names to pure values.
Otherwise, you've presumably done something like this:
main = do
line <- getLine
splitOn "x" line
You're using a [String], but you need an IO action. You need to do something with the pure result you've got to turn it into an IO computation.
You could print the list out, as GHCi would:
print :: (Show a) => a -> IO ()
Or you could use return, if you simply want to return the pure computation to be used in other IO actions:
return :: a -> IO a
It all depends on how you want to process the data.
compute fp = do
text <- readFile fp
let (a,b) = sth text
let x = data b
--g <- x
putStr $ print_matrix $ fst $ head $ x
It works when i get only first element but i want do this for all element on the list of pair.
When i write g<- x i got Couldn't match expected type `IO t0'
with actual type [([[Integer]], [[Integer]])]
You're inside the IO Monad here, so any time you write a "bind" arrow <-, the thing on the right side has to be an IO operation. So the short answer is, you don't want to use <- on the value x.
Now, it looks like you want to call print_matrix for each element of a list rather than a single element. In that case I think Macke is on the right track, but I would use mapM_ instead:
mapM_ (putStr . print_matrix . fst) x
should do the trick.
The reason is that you are explicitly saying you want to putStr each element, one at a time, but you don't care about the result of putStr itself.
It sounds like mapM might fit your bill: Monad a => (b -> a c) -> [b] -> a [c]
It's used to apply a monadic function to a list, and get a list back, in the monad