
#10034: Regression in mapM_ performance -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: ekmett Type: bug | Status: new Priority: normal | Milestone: 7.10.1 Component: Core Libraries | Version: 7.10.1-rc2 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Runtime | Unknown/Multiple performance bug | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Revisions: Phab:D632 -------------------------------------+------------------------------------- Comment (by dfeuer): Replying to [comment:1 simonpj]:
Can you offer a reproducible test case, and timing or allocation data?
I had one, and then I lost it. I wish I could give you one as a test case and for future analysis. It was something very simple, and the `mapM_` of 4.7 was consistently the same as the version in the linked differential, and both allocated less than the version currently in head. I believe it had to be an arity issue. Call arity wasn't catching it for some reason, so it needed input from the other arity analysis that it wasn't getting. Consider the current definition: {{{#!hs mapM_ f = foldr ((>>) . f) (return ()) }}} Taking apart the argument to `foldr` above gives {{{#!hs mapM_ f = foldr (\m -> (>>) (f m)) (return ()) }}} Now fuse this with `build g`: {{{#!hs mapM_ f (build g) = g (\m -> (>>) (f m)) (return ()) }}} Without knowing what the monad is, `mapM_` doesn't know that `(>>)` has arity 2, and relies on Call Arity analysis of `g`, which I imagine wasn't working in whatever example I was dealing with. What I propose below forces the arity up to 2, and is also significantly easier to read. {{{#!hs {-# INLINE mapM_ #-} mapM_ f = foldr (\m n -> f m >> n) (return ()) }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/10034#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler