Precedence of Infix Operators in Do Syntax

Hello, I was reading this block of code from http://jasani.org/2008/02/18/command-line-haskell-and-error-handling-example... main = do m <- hGetContents stdin nums <- mapM readM . lines $ m print (sum nums) `catch` (\e -> hPutStrLn stderr ("couldn't sum lines: " ++ show e)) readM :: (Monad m, Read a) => String -> m a readM s | [x] <- parse = return x | otherwise = fail $ "Failed to parse \"" ++ s ++ "\" as a number." where parse = [x | (x,_) <- reads s] I don't understand how line 5 works. I thought that the do notation there would be the same as: main = hGetContents stdin >>= \m -> mapM readM . lines $ m >>= \nums -> print (sum nums) >> `catch` (\e -> hPutStrLn stderr ("couldn't sum lines: " ++ show e)) But I don't understand how that makes any sense with that infix `catch`. It looks like catch doesn't even have a first argument. Please enlighten me. Thanks.

On Tue, Nov 22, 2011 at 11:03:51PM -0500, Avery Robinson wrote:
Hello,
I was reading this block of code from http://jasani.org/2008/02/18/command-line-haskell-and-error-handling-example...
main = do m <- hGetContents stdin nums <- mapM readM . lines $ m print (sum nums) `catch` (\e -> hPutStrLn stderr ("couldn't sum lines: " ++ show e))
readM :: (Monad m, Read a) => String -> m a readM s | [x] <- parse = return x | otherwise = fail $ "Failed to parse \"" ++ s ++ "\" as a number." where parse = [x | (x,_) <- reads s]
I don't understand how line 5 works. I thought that the do notation there would be the same as:
main = hGetContents stdin >>= \m -> mapM readM . lines $ m >>= \nums -> print (sum nums) >> `catch` (\e -> hPutStrLn stderr ("couldn't sum lines: " ++ show e))
Some experimentation shows that in fact, the first argument of `catch` is the *entire* do-block. That is, it is the same as main = (do m <- hGetContents stdin nums <- mapM readM . lines $ m print (sum nums) ) `catch` (\e -> hPutStrLn stderr ("couldn't sum lines: " ++ show e)) However, I don't understand why. I would have thought it invalid. Perversely, indenting the `catch` by one more space results in a valid program with different behavior (since it only applies to the print). -Brent

Hi On Tue, Nov 22, 2011 at 11:03:51PM -0500, Avery Robinson wrote:
main = do m <- hGetContents stdin nums <- mapM readM . lines $ m print (sum nums) `catch` (\e -> hPutStrLn stderr ("couldn't sum lines: " ++ show e))
Using Hammar's naive do-notation desugarer [1] your example code becomes: ---8<--- main = hGetContents stdin >>= \ m -> mapM readM . lines $ m >>= \ nums -> print (sum nums) `catch` (\ e -> hPutStrLn stderr ("couldn't sum lines: " ++ show e)) --->8--- Comparing this with "ghc -ddump-ds" (cleaned up by removing _xyz suffixes and type annotations) ---8<--- Main.main = System.IO.Error.catch (>>= (GHC.IO.Handle.Text.hGetContents GHC.IO.Handle.FD.stdin) (\ m -> >>= (GHC.Base.$ (GHC.Base.. (mapM readM) Data.List.lines) m) (\ nums -> print_aAV (sum_aAU nums)))) (\ e -> System.IO.hPutStrLn GHC.IO.Handle.FD.stderr (GHC.Base.++ (GHC.Base.unpackCString# "couldn't sum lines: ") (show e))) --->8--- confirms this. But why is that? The section on do expressions of the Haskell report [2] explains that in the end a do block is just an expression. And section 3.4 [3] states that "e1 op e2 = (op) e1 e2", which in our case translates to "e1 `catch` e2 = catch e1 e2" where e1 is the preceeding do block and e2 is the lambda expression. So, the line starting with `catch` is not part of the do block any more. Greetings Alex [1] https://gist.github.com/1341505 [2] http://www.haskell.org/onlinereport/exps.html#sect3.14 [3] http://www.haskell.org/onlinereport/exps.html#sect3.4
participants (3)
-
Alexander Bernauer
-
Avery Robinson
-
Brent Yorgey