Print map function's output list using mapM_ / putStrLn - haskell

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 ().

Related

How to use map to print a List in Haskell?

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;
}

How to separate a user inputted string by the spaces n in Haskell IO

I want to ask the user for a sentence, and then return the sentence back but with the words on separate lines.
For example, if the user inputs "hello I am tall", the computer returns:
hello,
I
am
tall
I tried to start off a bit, but don't know of a function or something I can use to try and separate the sentence. My code so far:
displayWords ::IO ()
displayWords = do putStr "Please enter a line of text"
x <- getLine
mapM print x
I get the error:
Couldn't match type ‘[()]’ with ‘()’
EDIT: One more side thing... using mapM_ print (words x) fixes what I want, but is there a way to print this without the quotation marks?
EDIT2: One more thing... Someone in the comments helped answer the previous edit, but if I change the format of this to
displayWords:: String -> IO Int()
displayWords s = do
mapM_ putStrLn s
return (length s)
I get the error
Couldn't match type 'Char' With '[Char]'
How come putStrLn doesn't work here?
You need the words function to split the string into separate words.
Someone suggested mapM_ print (words x), but since each word is a string, using print will wrap it in quote marks, which you don't want. So try
mapM_ putStrLn (words x)
Use mapM_.
mapM print returns a list, the result of calling print for each element, but since print returns just () that is [()] not very meaningful.
-- here, b = ()
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
mapM_ print discards the result of each call:
mapM_ :: Monad m => (a -> m b) -> [a] -> m ()
displayWords must be of type IO (), and the type of a do-block is the type of its last statement, this is why mapM results in a type error.
Another way would be to ignore the result of a function like mapM by adding a statement that does nothing.
do putStr "..."
x <- getLine
mapM print x
return ()

Map Function Doesn't Work as Intended

I have a couple of Haskell functions for writing to a .tex file (using the HaTeX package) which look like this:
theBody :: Monad m => [ Maybe (String, String)] -> LaTeXT_ m
theBody listOfEntries = do
maketitle
center $ tabular Nothing [RightColumn, VerticalLine, LeftColumn] $ do
textbf "Name" & textbf "Tel"
let removedJusts = map fromJust listOfEntries
map tableEntry removedJusts
tableEntry :: Monad m => (String, String) -> LaTeXT_ m
tableEntry (name, number) = do
lnbk
hline
do
textit (fromString name)
&
textit (fromString number)
When I run this code, I get the following error:
Couldn't match expected type ‘LaTeXT m ()’ with actual type ‘[LaTeXT_ m0]’
Arising from the line where I map the tableEntry function to my list of tuples. The list of tuples would look something like this:
[("A Name", "12345"), ("Another Name", "54321"), ("Yet Another Name", "98765")]
If I replace map tableEntry removedJusts with:
tableEntry (removedJusts !! 0)
tableEntry (removedJusts !! 1)
tableEntry (removedJusts !! 2)
It does indeed add these entries to my tex file, so I can't understand why the map function wouldn't work for the list.
Any help appreciated.
tableEntry (removedJusts !! 0) works because it matches the return type of your theBody function (LaTeXT_ m or, expanding the type synonym, LaTeXT m ()). map tableEntry removedJusts, on the other hand, gives a list of LaTeXT_ m, leading to the type error you have seen. What you actually need here is mapM_, which, in addition to mapping, combines all resulting LaTeXT m () computations in a single LaTeXT m ():
GHCi> :t mapM_
mapM_ :: (Foldable t, Monad m) => (a -> m b) -> t a -> m ()
theBody :: Monad m => [ Maybe (String, String)] -> LaTeXT_ m
theBody listOfEntries = do
maketitle
center $ tabular Nothing [RightColumn, VerticalLine, LeftColumn] $ do
textbf "Name" & textbf "Tel"
let removedJusts = map fromJust listOfEntries
mapM_ tableEntry removedJusts
P.S.: A closely related function that you will eventually find useful is traverse. Unlike mapM_, traverse collects, rather than discards, the results of each computation. (Here I used mapM_ becuase you do want to discard said results, as they are merely ().)
P.P.S.: Using fromJust is generally not a good idea. It will make your theBody crash with a generic error message if there is a Nothing in the input list. Better options include catMaybes (from Data.Maybe), which will silently filter out the Nothing values (e.g. let removedJusts = catMaybes listOfEntries), and maybe and fromMaybe (the latter also from Data.Maybe), which allow you to choose how to handle Nothing values.

Output Integer to stdout in Haskell

I have a simple function like:
nth :: Integer -> Integer
And I try to print it's result as follows:
main = do
n <- getLine
result <- nth (read n :: Integer)
print result
The following error is generated:
Couldn't match expected type `IO t0' with actual type `Integer'
In the return type of a call of `nth'
In a stmt of a 'do' expression:
result <- nth (read n :: Integer)
Also tried with putStrLn and a lot of other combinations with no luck.
I can't figure it out and I would need some help, being that I don't fully understand how stuff works around these IOs.
nth is a function, not an IO action:
main = do
n <- getLine
let result = nth (read n :: Integer)
print result
The do syntax unwraps something within a monad. Everything on the right hand side of the arrow must live within the IO monad, otherwise the types don't check. An IO Integer would be fine in your program. do is syntactic sugar for the more explicit function which would be written as follows:
Recall that (>>=) :: m a -> (a -> m b) -> m b
main = getLine >>= (\x ->
nth >>= (\y ->
print y))
But nth is not a monadic value, so it doesn't make sense to apply the function (>>=), which requires something with the type IO a.

Haskell monadic IO

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

Resources