Avoiding full laziness xform / floating-out (Re: What's the benefit of taking "do" blocks apart? Is there a way to turn that off?)

Erdi, Gergo Gergo.Erdi at sc.com
Thu Dec 30 09:03:37 UTC 2021


PUBLIC

Hi Joachim,

Thanks for the hints!

> Hi Gergo,
> 
> Am Dienstag, dem 28.12.2021 um 15:57 +0000 schrieb Erdi, Gergo via ghc-
> devs:
> > PUBLIC
> 
> phew

Yeah obviously I'm sitting here not only adding these tags, but also
coming up with the automated systems and also the company policies
forcing the usage of said systems ;)

> didn't investigate deeper (maybe if you provide a small example I would), but just from looking at this:

Unfortunately, it's hard to make a small example because this all
lives in bizarro world where "IO" isn't IO, "String" isn't [Char] etc,
so I can't just take the input program and pass it to vanilla GHC.

> 
>  * It is generally preferable to turn local lambda expressions
>    into top-level functions. This way, instead of dynamically
>    allocating a FUN heap object, it's just a static function.
> 
>  * sat_sKv is an IO expression? Then it is actually a function in a way
>    (taking the "State token" as an argument). So the above applies.

This is "IO" but not GHC's IO, just another type with an opaque
definition and a Monad instance. There's no reason for GHC to think
that sat_sKv would be a function.

Of course, sat_sKw is necessarily a function since it is the second
argument to bind. But only now I am noticing that even sat_sKw's
definition includes *yet another* floated-out variable:

sat_sKv = some complicated expression 1
sat_sKu = some complicated expression 2
sat_sKw = \_ -> sat_sKu
main = bindIO sat_sKv sat_sKw

Here, I don't see why GHC should think that sat_sKv and sat_sKu are
functions. For example, here's the definition of sat_sKu:

sat_sKu :: IO ()
[LclId]
sat_sKu
  = let {
      sat_sRy [Occ=Once1] :: String
      [LclId]
      sat_sRy
        = let {
            sat_sRx [Occ=Once1] :: String
            [LclId]
            sat_sRx = unpackCStringUtf8# "\n"# } in
          let {
            sat_sRw [Occ=Once1] :: String
            [LclId]
            sat_sRw
              = case foobar True of {
                  False -> unpackCStringUtf8# "False"#;
                  True -> unpackCStringUtf8# "True"#
                } } in
          sApp# sat_sRw sat_sRx } in
    putStrOut sat_sRy

Here, putStrOut is so opaque that it doesn't even have a definition,
it is merely a name registered into GHC's name tables. So I really
don't see why this looks "function-y" to GHC.

The reason this is all a problem for me is because I would like to
then interpret all these let-bindings, including the toplevel ones, as
eagerly defined variables. But then there is of course a difference between

main =
  let a1 = someIOAction1
      a2 = someOtherIOAction2
      a2' = \_ -> a2
  in bindIO a1 a2'

and

main =
  let a1 = someIOAction1
      a2 = \_ -> someIOAction2
  in bindIO a1 a2

because if the *definition* of "a2" throws (not its action), then the
first version will throw immediately whereas the second will only
throw when "main" is *run*, after running "a1".

>  * I think this is the FloatOut pass. You can turn it out using
>    -fno-full-laziness. Not sure if some others passes might
>    do similar things, though.

I tried turning off Opt_FullLaziness, but unfortunately I am still
getting the same result. I was also hopeful when I saw there's an
Opt_FloatIn flag, but alas that doesn't change this behaviour either
(and it's turned on by default anyway...)

I'll try to make a self-contained minimal example next week.

Thanks,
        Gergo

-----Original Message-----
From: ghc-devs <ghc-devs-bounces at haskell.org> On Behalf Of Joachim Breitner
Sent: Wednesday, December 29, 2021 8:39 PM
To: ghc-devs at haskell.org
Subject: [External] Re: What's the benefit of taking "do" blocks apart? Is there a way to turn that off?

[You don't often get email from mail at joachim-breitner.de. Learn why this is important at http://aka.ms/LearnAboutSenderIdentification.]

ATTENTION: This email came from an external source. Do not open attachments or click on links from unknown senders or unexpected emails. Always report suspicious emails using the Report As Phishing button in Outlook to protect the Bank and our clients.


Hi Gergo,

Am Dienstag, dem 28.12.2021 um 15:57 +0000 schrieb Erdi, Gergo via ghc-
devs:
> PUBLIC

phew

> I’m seeing ‘do’ blocks getting taking apart into top-level 
> definitions, so e.g.
>
> main = do
>   some complicated expression 1
>   some complicated expression 2
>
> is compiled into
>
> sat_sKv = some complicated expression 1 sat_sKw = \_ -> some 
> complicated expression 2 main = bindIO sat_sKv sat_sKw
>
> This seems to happen regardless of any common subexpressions, i.e. it 
> is not the case that sat_sKv or sat_sKw are used anywhere else.
>
> What is the intended benefit of this floating-out? Is there a 
> particular Core-to-Core pass that causes this? Is it possible to turn 
> it off?


didn’t investigate deeper (maybe if you provide a small example I would), but just from looking at this:

 * It is generally preferable to turn local lambda expressions
   into top-level functions. This way, instead of dynamically
   allocating a FUN heap object, it’s just a static function.

 * sat_sKv is an IO expression? Then it is actually a function in a way
   (taking the “State token” as an argument). So the above applies.

 * I think this is the FloatOut pass. You can turn it out using
   -fno-full-laziness. Not sure if some others passes might
   do similar things, though.

Cheers,
Joachim


--
Joachim Breitner
  mail at joachim-breitner.de
  https://clicktime.symantec.com/33oTTj3Bye1kkqsmxZWi3QZ6xU?u=http%3A%2F%2Fwww.joachim-breitner.de%2F

_______________________________________________
ghc-devs mailing list
ghc-devs at haskell.org
https://clicktime.symantec.com/3bo4KFUFPcVSdMe4B1CUzr6xU?u=http%3A%2F%2Fmail.haskell.org%2Fcgi-bin%2Fmailman%2Flistinfo%2Fghc-devs

This email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please delete all copies and notify the sender immediately. You may wish to refer to the incorporation details of Standard Chartered PLC, Standard Chartered Bank and their subsidiaries at https: //www.sc.com/en/our-locations

Where you have a Financial Markets relationship with Standard Chartered PLC, Standard Chartered Bank and their subsidiaries (the "Group"), information on the regulatory standards we adhere to and how it may affect you can be found in our Regulatory Compliance Statement at https: //www.sc.com/rcs/ and Regulatory Compliance Disclosures at http: //www.sc.com/rcs/fm

Insofar as this communication is not sent by the Global Research team and contains any market commentary, the market commentary has been prepared by the sales and/or trading desk of Standard Chartered Bank or its affiliate. It is not and does not constitute research material, independent research, recommendation or financial advice. Any market commentary is for information purpose only and shall not be relied on for any other purpose and is subject to the relevant disclaimers available at https: //www.sc.com/en/regulatory-disclosures/#market-disclaimer.

Insofar as this communication is sent by the Global Research team and contains any research materials prepared by members of the team, the research material is for information purpose only and shall not be relied on for any other purpose, and is subject to the relevant disclaimers available at https: //research.sc.com/research/api/application/static/terms-and-conditions. 

Insofar as this e-mail contains the term sheet for a proposed transaction, by responding affirmatively to this e-mail, you agree that you have understood the terms and conditions in the attached term sheet and evaluated the merits and risks of the transaction. We may at times also request you to sign the term sheet to acknowledge the same.

Please visit https: //www.sc.com/en/regulatory-disclosures/dodd-frank/ for important information with respect to derivative products.


More information about the ghc-devs mailing list