Print list items in new lines

I'm just completely confused by lists and monads, so maybe my question is not correct or very naive. I saw a way to do this using mapM_ func here :

mapM_ print [1, 2, 3, 4] 

But I donโ€™t know exactly how it works, and I want to know how I can do it as follows:

 x <- [1, 2, 3] print x 

or, if I understood correctly:

 [1, 2, 3] >>= print 

I understand that [1, 2, 3] is of type [a] , and print is of type Show a => a -> IO () . I also understand that to use monad List, we need List a on the left and func with a -> List b on the right. I'm right? Can you help me?

UPD Thanks to @MathematicsOrchid for how mapM_ works. For my part, I want to explain that the real problem is not to print the results in different lines, but to perform some monadic actions (because now I hang around OpenGL things), as the monad List does. But I realized that the root of the misunderstanding was mixing monads.

UPD2 . Thanks everyone for the answers. I apologize for this fuzzy question. I donโ€™t know exactly what answer I need and what the question is. This is because I did not understand some of the basics. Therefore, it is difficult to choose the โ€œright answerโ€ now, because each answer has a small world that I was looking for. I decided to choose the closest (though not the most useful now) to what I wanted.

+4
source share
5 answers

What you want cannot work this way because you are trying to combine two monads:

 do x <- [1,2,3] print x 

In particular, you mix monads IO and [] . In do-notation, all statements must be of type ma for some Monad m . But in the above code, the first operator is of type [Integer] , and the second operator is of type IO () .

To get the desired effect, you should use a ListT monad transformer. Monad transformers allow you to mix monads together in a specific order on the stack and combine their effects as needed.

 import Control.Monad.Trans import Control.Monad.Trans.List value = do x <- ListT (return [1,2,3]) lift (print x) 

This will return a value of type ListT IO Integer . To get the IO calculation from this transformer, use runListT . Which will return a value of type IO [Integer] . This will output:

 GHCI> runListT value 1 2 3 [(),(),()] 

This is equivalent to mapM print [1,2,3] . To throw away the list and get the effect mapM_ print [1,2,3] , you can use void from Control.Monad .

 GHCI> void . runListT $ value 1 2 3 
+9
source

You seem to have a few things confused here. (In particular, lists form a monad, and I / O forms another monad.) I will try to clear this ...

First of all, the print function prints something indicative and writes it to the standard one, and then to a new line. So, print [1, 2, 3] works just fine, but obviously it writes everything on one line. To write material on separate lines, we need a separate print call for each element. So far so good.

The map function applies the function to each element of the list. Thus, map print [1, 2, 3] apply print to each element in the list. However, the result is a list of I / O actions. And this is not exactly what we need. We want to perform these actions, not list them.

The way to do this is to use the >> operator, which combines the two I / O actions (provided that they are not interested in their results), and printing something does not return anything interesting). So foldr (>>) (return ()) will take your list of I / O operations and turn it into a single I / O action. This function is actually already defined; it is called sequence .

However, map + sequence is such a common combination that it is also already defined; it is called mapM_ . (There is mapM , without underlining, if you want to save the results, but printing does not return anything, so there is no need.)


Now, why mapM_ works. Now you are asking why several other ways will not work ...

 x <- [1, 2, 3] print x 

This does not work at all. The first line is in the list of monads. But the second line is in the I / O monad. You cannot do this. (You will have a rather complex type-checking error.) I should probably point out that this is Haskell, the so-called "do-notation", and this snippet requires the do keyword on the front panel so that it really has strong syntax

 do x <- [1, 2, 3] print x 

In any case, this still does not work. It almost does what map print [1, 2, 3] does, but not quite. (As I said, he will not check the type.)

You also suggested [1, 2, 3] >>= print , which is identical to the previous snippet. (In fact, the compiler converts the first to the last.) The original does not check the type, and for the same reason, it does not check the type.

This is a bit like trying to add a number to a matrix. Numbers are extra things. Matrices are additional things. But you cannot add each other because they do not match. If that makes sense.

+12
source

You can use sequence_ to perform IO actions in the following order:

 sequence_ $ [1, 2, 3] >>= (\x -> [print x]) 

But I think mapM_ much clearer.

+5
source

I will not answer your question exactly, because I think the question itself is a bit wrong. In particular, using mapM or something similar is what you need to do here. Using notation for this task will only complicate the situation, and I have an aversion to telling people things that are not suitable. But I will give you an alternative that you might find easier to grasp.

If you are coming from an imperative background (for example, you are familiar with something like C, Java, Python ...), it might be easier for you to use forM rather than mapM . Syntax

 forM <list of things> <action to perform for each thing> 

i.e. it's just like for every cycle! For instance:

 ghci> import Control.Monad ghci> forM [1,2,3] print 1 2 3 [(),(),()] 

The list of things [1,2,3] , and the action for each thing is print . Notice the return value at the end? This is because each call to print returns () , and they come together at the end. If you do not want to use the return value, use forM_ instead of forM , for example:

 ghci> forM_ [1,2,3] print 1 2 3 

Are you ready for a secret? The forM and forM_ are simply mapM and mapM_ with the arguments changed, mapM_ .:

 forM list action = mapM action list 

I often use forM in my code because it draws attention to the function, not the list that you often need. It also looks tidier if then the function spans multiple lines.

+4
source

Here is perhaps the simplest explanation of how mapM_ works:

 main = foldr1 (>>) (map print [1, 2, 3]) 

That is, print is applied to each element of the list, and the results are combined using >> , so first you get

 main = foldr1 (>>) [print 1, print 2, print 3] 

and in the end you get

 main = print 1 >> print 2 >> print 3 

A bit more accurate explanation:

 main = foldr (>>) (return ()) (map print [1, 2, 3]) 

So in the end you get

 main = print 1 >> print 2 >> print 3 >> return () 

The return () allows you to work with an empty list - foldr1 simply reset in the empty lists the same head and tail do.

+1
source

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


All Articles