Constructor wrappers vs workers in generated Core

Christopher Done chrisdone at gmail.com
Fri Feb 8 13:23:08 UTC 2019


Sorry, here's my explanation.

In summary, I was trying to go for the cleanest, tidiest, simplest AST
possible for interpretation. My long-term goal is to have a slow but
working interpreter of GHC Haskell written in Haskell that is capable
of hot-swapping without segfaulting, by gracefully handling changing
types and functions (just report a type error like the Lisps do), and
the short-term goal is to export that interpretable AST as a web
service so that a simple JS interpreter and/or substitution stepper
could be written for the purposes of education, like
https://chrisdone.com/toys/duet-delta/.

I think this mailing list thread turns out to be an x/y problem. I need STG.

I ended up doing lots of cleaning steps to generate a more well-formed
Core. I learned that the Core that comes from the desugarer is
incomplete and realized today that I was duplicating work done by the
transformation that converts Core to STG. I'd initially avoided STG,
thinking that Core would suffice, but it seems that STG is the AST
that I was converging on anyway. It seems that STG will have all class
methods generated, wrappers generated (and inlined as appropriate),
primops and ffi calls are saturated, etc. no Types or coercions, etc.
It even has info about whether closures can be updated and how.

I wish I'd chosen STG instead of Core from the beginning, but it
doesn't set me back by much so I'll consider this a learning exercise.
If anything, it makes me appreciate almost everything going on in STG
for why it's there and is useful.

I'm aware of two projects that interpret their own form of STG:

http://hackage.haskell.org/package/stgi
http://hackage.haskell.org/package/ministg

But I intend on consuming directly the STG AST from GHC.

The bulk of the work I did that will stay useful is managing a global
mapping of Ids, in terms of global, local ids, and conids in separate
namespaces. IOW I replace all Ids in the AST with a globally unique
Int, like Unique, but it preserves across separate runs, rather than
being per GHC run. So I can plug that work into the STG AST instead. I
have a Docker file that compiles a patched GHC and outputs my AST for
ghc-prim, integer-gmp and base, that leads to all these files:

https://gist.github.com/chrisdone/5ed9adf9dba5fd82d582e9f2bbc30c9f

which have Ids that reference eachother cross-module/package without
any need for more fiddling/munging. The AST looks like this

https://github.com/chrisdone/prana/blob/eaa5b2111631c13eb6b41c9a47400a4ba6a09ffa/test/Main.hs#L164..L198

then I have a mapping from Int64->Name for debugging. I think having
an STG representation that tools like ministg/stgi can consume that
includes everything (ghc-prim, integer-gmp and base) is handy, aside
from my own use-cases (giving the AST to a web app and "real"
interpreting).

Cheers!

On Mon, 4 Feb 2019 at 17:56, Matthew Pickering
<matthewtpickering at gmail.com> wrote:
>
> If you want your core to look at much like the source program as
> possible then you could print `$WFoo` as just `Foo`?
>
> The existence of wrappers is a crucial part of desugaring so perhaps
> it's useful for users to see them in the output of your program if
> it's intended to be educational?
>
> Matt
>
>
> On Sat, Feb 2, 2019 at 3:06 PM Christopher Done <chrisdone at gmail.com> wrote:
> >
> > On Sat, 2 Feb 2019 at 14:50, Matthew Pickering
> > <matthewtpickering at gmail.com> wrote:
> > > There is no way to turn off wrappers and I don't think it would be
> > > possible to implement easily if at all.
> >
> > Fair enough.
> >
> > > However, they will all probably be inlined after the optimiser runs
> > > but it seems that you don't want to run the optimiser at all on the
> > > generated core?
> >
> > Yeah, I'm trying to avoid as much instability in the output shape as
> > possible, and for educational purposes, optimizations make fairly
> > readable code unreadable.
> >
> > Wait. Can I rely on case alt patterns having the same arity as the
> > original user-defined data type before optimization passes are run?
> >
> > If the answer to that is yes, then I could just replace all wrapper
> > calls with worker calls, which is an easy enough transformation. As a
> > precaution, I could add a check on all case alt patterns that the
> > arity matches the worker arity and barf if not.
> >
> > Thanks for your help!
> >
> > Chris


More information about the ghc-devs mailing list