3

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?

5
  • You are mapping over a list, not an array. What is map's type? What is putStrLn's type? Commented May 29, 2021 at 23:55
  • @MichaelLitchard I wiil rectify the Array/list, but puStrLn Type in defined in the System.IO standard module. (It should be String -> IO ()) Commented May 30, 2021 at 0:02
  • 1
    Use traverse instead -- it's like map but for monadic actions like putStrLn Commented May 30, 2021 at 0:06
  • @luqui 1. How is defined traverse?, 2. not the error is Couldn't match type ‘[()]’ with ‘()’ 8 Expected type: IO () 7 Actual type: IO [()] 3. I just change map with traverse. Commented May 30, 2021 at 0:17
  • Here you'd want a single IO action, not a list of IO actions. And library function map gives you such a list :-( - but then you might want to have a look at the sequence_ library function Commented Sep 1, 2024 at 21:37

2 Answers 2

4

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;
}
Sign up to request clarification or add additional context in comments.

2 Comments

I don't think there's any lisp where (print 3) evaluates to 3. Maybe in some it evaluates to "3", but usually it evaluates to nil, the local equivalent of ().
@amalloy In common lisp, (print 3) evaluates to 3. Try (let ((x (print 3))) (= x 3)), for example.
1

The main requires IO monad, so you need to map inside the IO monad not List of IO as the error said. The mapM_can do the work. mapM_ eats monadic function and list of something and it maps inside the monad. The result will be IO () while printing strings.

array = map show [1, 2, 3, 4]

main :: IO ()
main = do
  mapM_ putStrLn array

This is the result:

1
2
3
4

1 Comment

Favorite answer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.