Home > Net >  Haskell mapM_ does not print
Haskell mapM_ does not print

Time:04-10

So I wrote a program to query a forex API (foreign exchange), and it works like a charm, but when I want to query every currency pair available, it evaluates all API calls as it takes a long time to execute but prints nothing.

import Data.Functor ((<&>))

supportedPairs :: IO (Maybe [(String, String)])
forex :: String -> String -> IO (Maybe (Scientific, UnixTime))


main :: IO ()
main = do
    x <- supportedPairs
    mapM_ (flip (<&>) print . uncurry forex) (fromJust x)
    -- this prints nothing at all

The single calls work just fine like this:

main = do
    x <- supportedPairs    
    u <- (uncurry forex . (flip (!!) 10 . fromJust)) x
    print u
    -- this prints "Just (438.685041,UnixTime {utSeconds = 1649588583, utMicroSeconds = 0})"

Why doesn't the mapM_ print the results although they are evaluated? If I understood Haskell's laziness correctly, then if the results are not to be printed they should not be evaluated in the first place?

CodePudding user response:

Check the types:

print is ... -> IO ().

Therefore, ... <&> print is IO (IO ()). Note the double IO here.

Hence, mapping over that, will run the "outermost IO" but not the "innermost IO". More concretely, compare this:

main = do
  x <- print True >> return 5          -- x is 5
  y <- return (print True >> return 5) -- y is an IO action
  ...

Only the first print True here is executed: the second IO action is used to define y but until we run y it won't be executed.

The final point: here, you do not need <&> since that creates the nested IO's. Use flip (>>=) print (or (=<<) print, or (>>= print)) instead of flip <&> print.

  • Related