
I solved the hacker-rank hello world n times challenge thus: hello_worlds :: Int -> IO () hello_worlds n | n < 1 = return () | otherwise = do putStrLn "Hello World" hello_worlds (n-1) main :: IO() main = do n <- readLn :: IO Int hello_worlds n I would like to solve this by using the interact function. If I leave my hello_worlds function as is and change the main function as follows: main = interact $ show . hello_worlds . read::Int I get: Couldn't match expected type ‘IO t0’ with actual type ‘Int’ • In the expression: main When checking the type of the IO action ‘main’ helloworlds.hs:14:8-44: error: • Couldn't match expected type ‘Int’ with actual type ‘IO ()’ • In the expression: interact $ show . hello_worlds . read :: Int In an equation for ‘main’: main = interact $ show . hello_worlds . read :: Int could someone please explain why this can't work? Is it possible to use interact in such a context? Thanks

Ciao Michele, On Sun, Feb 10, 2019 at 05:10:13PM +0100, Michele Alzetta wrote:
If I leave my hello_worlds function as is and change the main function as follows:
main = interact $ show . hello_worlds . read::Int
I get: [...]
helloworlds.hs:14:8-44: error: • Couldn't match expected type ‘Int’ with actual type ‘IO ()’ • In the expression: interact $ show . hello_worlds . read :: Int In an equation for ‘main’: main = interact $ show . hello_worlds . read :: Int
Two facts: - (.) is an operator which concatenates function - to concatenate functions, input/outputs must match So let's analyse this: 1. `read` has type `Read a => String -> a` 2. `hello_worlds` has type `Int -> IO ()` 3. `show` has type `Show a => a -> String` and there is no way to convert `IO ()` to `String`. Remember that hello_worlds does *not* return a series of Strings, but an IO action (in this case, "blit something to screen") Your `interact` example would function if written like this: main = interact $ unlines . map (hello_pure . read) . lines -- with `hello_pure :: Int -> String` `lines` and `unlines` are there to keep input lazy for each line. Do you think you can you fill-in "hello_pure" yourself? -F

Francesco, thanks, that was very enlightening. That concatenated functions should have matching inputs / outputs is obvious of course, but I just didn't think of that. Duh! That IO () can't be converted to String is probably just as obvious, but it wasn't for me. For hello_pure I tried this: hello_pure :: Int -> String hello_pure n | n < 1 = "" | otherwise = "Hello World" ++ "\n" ++ hello_pure ( n - 1 ) And it works, although ++ "\n" ++ doesn't feel so elegant.

On Sun, Feb 10, 2019 at 09:59:54PM +0100, Michele Alzetta wrote:
For hello_pure I tried this:
hello_pure :: Int -> String hello_pure n | n < 1 = "" | otherwise = "Hello World" ++ "\n" ++ hello_pure ( n - 1 )
Very good!
And it works, although ++ "\n" ++ doesn't feel so elegant.
If you want, you can rewrite is as a one-liner like this: hp2 :: Int -> String hp2 n = unlines $ replicate n "Hello world" -F
participants (2)
-
Francesco Ariis
-
Michele Alzetta