1

I don't understand why this happens:

module Main where

import Control.Monad.Reader

data Config = Config Int

getA :: (Monad m) => ReaderT Config m Int
getA = do
  Config a <- ask
  return a

readConfig :: Config -> IO Int
readConfig = runReaderT getA

main :: IO ()
main = do
  print "Start"
  let a = Config 2
  b <- readConfig a -- Will be printed
  print b
  let c = Config 4
  print <$> readConfig c -- Silence, nobody complains..
  print "Done"

the result is just:

"Start"
2
"Done"

Why is print <$> readConfig a empty? Even with -Wall nobody complains about this...

(I tried diff ghc versions in godbolt but the result stays the same)

Edit: Ok, I found an equivalent description of the problem, thx to @chi and @David:

module Main where
test :: IO ()
test = do 
    print "test"
    return ()

main :: IO ()
main = do
  let t = test -- equivalent to print <$> readConfig c, is IO (IO ())
  test -- equivalent to print b is IO ()

Now, I'm just wanting to know why let t does not evaluate. From my intuition, it was obvious before but not anymore... But there are answers to this (esp. from Tanner Swett)

  • 1
    `do { a <- foo; return a }` can also be spelled `foo` -- it's a `Monad` law! – Daniel Wagner Oct 08 '21 at 15:57
  • Related example: `x <- print 3` prints 3 and binds `()` to `x`, while `x <- return (print 3)` doesn't print anything, and binds the IO action `print 3` to `x`. – chi Oct 08 '21 at 16:38
  • chi and @Daniel, I appreciate your comments, but I do not understand how I should apply them to my problem. Do you want to point out some identity function for Monads? Is it somehow related to the answer from David? – blauerreimers Oct 08 '21 at 20:40
  • @blauerreimers The refactor I suggest (compare your definition of `readConfig` to the template in my comment) is unrelated to your problem. It has to be -- it's a `Monad` law! That's (part of) why I posted this as a comment rather than an answer. Also, I believe chi's comment is unrelated to mine; the "Related example" opener is justified by it being closely related to your problem. – Daniel Wagner Oct 08 '21 at 20:43
  • @Daniel Ah, typical tunnel vision syndrome - I did not look anywhere above the main block and didn't see the connection...refactoring! ty – blauerreimers Oct 08 '21 at 20:54
  • @chi Ah, ok, I see now. It guess it is the same additional question to the answer from David. I wonder why `()` gets evaluated (from `x <- print 3), while `( IO () )` doesn't' (from `x <- return (print 3)`). – blauerreimers Oct 08 '21 at 21:07
  • @blauerreimers Because IO action execution only happens when you do something like `... <- x`, otherwise you simply pass the action around without running it. You can roughly think of an IO action as an OOP object with a method "run": passing the object around, returning it, copying it, etc. does not call the method. It's the same principle used in [this answer](https://stackoverflow.com/questions/28624408/equal-vs-left-arrow-symbols-in-haskell/28625714#28625714). – chi Oct 08 '21 at 23:03

1 Answers1

6

GHC 8.10.3 does complain about this with -Wall (after I changed initConfig to readConfig in your code):

A do-notation statement discarded a result of type ‘IO ()’
Suppress this warning by saying ‘_ <- print <$> readConfig c’

You have readConfig c of type IO Int. Then you fmap print, giving something with a type of IO (IO ()). Since the result isn't bound to a variable in the do block, it is thrown away.

In the fmap's type Functor f => (a -> b) -> f a -> f b we have f being IO, a being Int, and b being IO (). So it is used with the type (Int -> IO ()) -> IO Int -> IO (IO ()).

This would work:

printAction <- print <$> readConfig c
printAction

But what you actually want is a bind:

print =<< readConfig c
David Fletcher
  • 2,590
  • 1
  • 12
  • 14
  • Ty, this is still a hard nut to me: `IO (IO ())` does not get evaluated, because it is not used - this makes sense to me. But the monad `=<<` does ( `IO ()` ). Is it because, of the operation from `IO( IO ())` to `IO ()`? (Still, I ignore the result, so why is it evaluated?). – blauerreimers Oct 08 '21 at 19:29