[GHC] #13080: Memory leak caused by nested monadic loops

GHC ghc-devs at haskell.org
Fri Jan 13 14:32:44 UTC 2017


#13080: Memory leak caused by nested monadic loops
-------------------------------------+-------------------------------------
        Reporter:  Feuerbach         |                Owner:
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:  8.2.1
       Component:  Compiler          |              Version:  8.0.1
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
 Type of failure:  Runtime           |  Unknown/Multiple
  performance bug                    |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by nomeata):

 >  do we intend for bar to be recomputed on each call to foo, or shared
 globally?

 The answer to this question depends heavily on what it means for “foo” to
 be called! Consider this:

 {{{#!hs
 foo :: Int -> IO ()
 foo x = …
   where bar = expensive x
 }}}

 If we now run `mapM (foo 1) [1.1000]`, then, in one sense, the function
 `foo` is called once (when passed `x`). This returns a value of type `IO
 ()`, which is then executed 1000 times. This is the sense that the
 compiler understands, and without further hacks, `bar` would be evaluated
 only once here. Some users know and expect this.

 But there is another sense where one thinks of a call to `foo` as the
 execution of the `IO` action produced by `foo 1`. This is probably how
 most users in most cases think about functions returning an `IO`
 something. . With the current implementation of `IO ()`, this is when the
 state token is passed to the function wrapped in `IO ()`.

 The state hack is about eta-expanding `foo` so that these notions
 coincide. Unfortunately, and as far as I can tell, there is no way of
 writing `foo` to get this result directly (without breaking the `IO`
 abstraction barrier).

 The same distinction works for other monads, of course: `foo 1` might
 return a `Parser ()`, and we have the distinction between calculating the
 parser, and applying it to some input. And, in extension, with an
 arbitrary `Monad` the distinction is even more evident.

 So in this thread, we should be very precise which form of “calling” is
 the right one.

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/13080#comment:20>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list