# Repeated computations under a lambda

Conal Elliott conal at conal.net
Tue Jul 18 22:51:57 UTC 2017

```> the exampleC is the bound things that is eta-expanded.

Oh! I get it now. Thanks.

> The problem is that GHC’s optimizer uses a cost-model [...] that does not

Makes sense a well. I'll use `-fno-do-lambda-eta-expansion` for now and see
well it works.

Thanks very much for these tips.

Regards, - Conal

On Tue, Jul 18, 2017 at 3:44 PM, Joachim Breitner <mail at joachim-breitner.de>
wrote:

> Hi Conal,
>
> Am Dienstag, den 18.07.2017, 15:35 -0700 schrieb Conal Elliott:
> > Thanks very much for this reply, Joachim. I see that `-fno-do-lambda-
> > eta-expansion` with my example prevents moving the computation under
> > the lambda where it gets repeatedly evaluated. I don't understand
> > what this code motion/substitution has to do with eta-expansion. Is
> > it that the `let` expression itself is eta-expanded? The GHC Users
> > Guide describes this flag as "eta-expand let-bindings to increase
> > their arity", which doesn't seem to fit here, since the `let`-
> > bindings are not function-valued (though the `let` expression is).
>
> In the code
>
> exampleC :: Double -> Double -> Double
> exampleC = \ t -> let s = sin t in \ x -> x + s
>
> the exampleC is the bound things that is eta-expanded. Ok, it is a top-
> level function, but that does not make a big difference. When eta-
> expanded, it becomes
>
> exampleC :: Double -> Double -> Double
> exampleC = \ t y -> (let s = sin
> t in \ x -> x + s) y
>
> and from then on, usual simplifications kick in to produce
>
> exampleC :: Double -> Double -> Double
> exampleC = \ t y -> let s = sin t in y + s
>
> and eventually
>
> exampleC :: Double -> Double -> Double
> exampleC = \ t y -> y + sin t
>
> (I ignore the unboxing of Doubles here).
>
>
> > > Did you measure whether this really is a problem? The benefits of not
> > > dealing with dynamically allocated functions might outweigh the cost of
> > > recalculating sin.
> >
> > No, I haven't measured. In this case, I'm compiling Haskell to GLSL
> > for execution on a GPU, where the inner lambda will be over space,
> > which means at least one application per pixel, so the computations
> > moved under the inner lambda will be redundantly computed a few
> > millions of times per frame (and much more with anti-aliasing).
> > Instead, I want to move those calculations to once per frame and
> > stored in quickly accessed video memory. As the space-independent
> > computation gets more complex, I expect the saving to grow.
>
> Hmm. The problem is that GHC’s optimizer uses a cost-model (in this
> case: calling an anonymous function is worse than recomputing sind)
> that does not hold in your case. Besides simply turning off some
> transformations, I am not sure what best you could do to avoid this…
>
> Gruß,
> Joachim
> --
> Joachim Breitner
>   mail at joachim-breitner.de
>   http://www.joachim-breitner.de/
>
> _______________________________________________
> ghc-devs mailing list