
That's right there are some missing bindings at the core level, those will
be generated by *corePrepPgm* function.
STG is a low level version of core and it contains all code that is
required for execution. Classes are represented as nodes (dictionary) at
STG level.
E.g. here is my custom STG data type which I export:
https://github.com/grin-tech/ghc-grin/blob/master/ghc-dump-core/GhcDump_StgA...
In my opinion GHC core has lots of internal coding convention.
Cheers
On Sat, Dec 1, 2018 at 4:02 PM Christopher Done
Regarding classes,
Csaba, did you have to deal with dictionaries at the STG level? I'm finding that at the Core level, methods don't generate code, so I have to generate them myself. But then I have to know more about classes than I might ideally not want to.
For example, I've noticed that if a class has only one method, then the dictionary for an instance doesn't actually seem to construct a record, but makes a special case and just refers to the single method. So my evaluator failed on this. If I add one more method to the class, then things work properly. Example:
module Demo (demo) where class Person a where person :: a -> Int wibble :: a -> Int instance Person X where person unusedarg = 5 wibble _ = 9 data X = X demo = person X
This produces
chris@precision:~/Work/chrisdone/prana$ sh scripts/compiledemo.sh [1 of 1] Compiling Demo ( Demo.hs, Demo.o ) Writing main_Demo.prana Eval: ((main:Demo.person main:Demo.$fPersonX) main:Demo.X) Eval: (main:Demo.person main:Demo.$fPersonX) Eval: main:Demo.person Done: main:Demo.person[Method]0 Eval: main:Demo.$fPersonX <---- here is the dictionary, and you can see what it refers to below: Eval: ((main:Demo.C:Person main:Demo.$cperson) main:Demo.$cwibble) <-- this is the two methods Eval: (main:Demo.C:Person main:Demo.$cperson) Eval: main:Demo.C:Person Done: (main:Demo.C:Person[Con] ) Done: (main:Demo.C:Person[Con] main:Demo.$cperson) Done: (main:Demo.C:Person[Con] main:Demo.$cpersonmain:Demo.$cwibble) Done: (main:Demo.C:Person[Con] main:Demo.$cpersonmain:Demo.$cwibble) Eval: main:Demo.$cperson Eval: (\main:Demo.unusedarg -> (ghc-prim:GHC.Types.I# 5)) Done: (\main:Demo.unusedarg -> (ghc-prim:GHC.Types.I# 5)) Done: (\main:Demo.unusedarg -> (ghc-prim:GHC.Types.I# 5)) Done: (\main:Demo.unusedarg -> (ghc-prim:GHC.Types.I# 5)) Eval: (ghc-prim:GHC.Types.I# 5) Eval: ghc-prim:GHC.Types.I# Done: (ghc-prim:GHC.Types.I#[Con] ) Done: (ghc-prim:GHC.Types.I#[Con] 5) Done: (ghc-prim:GHC.Types.I#[Con] 5) ConWHNF (Id {idStableName = "ghc-prim:GHC.Types.I#", idUnique = Unique 3891110078048108563, idCategory = DataCat}) [LitE (Int 5)]
That's great. But if I delete the wibble method:
Eval: ((main:Demo.person main:Demo.$fPersonX) main:Demo.X) Eval: (main:Demo.person main:Demo.$fPersonX) Eval: main:Demo.person Done: main:Demo.person[Method]0 Eval: main:Demo.$fPersonX <- the dictionary Eval: main:Demo.$cperson <-- evaluates to simply the person method, instead of a data constructor Eval: main:Demo.$cperson Eval: (\main:Demo.unusedarg -> (ghc-prim:GHC.Types.I# 5)) Done: (\main:Demo.unusedarg -> (ghc-prim:GHC.Types.I# 5)) Done: (\main:Demo.unusedarg -> (ghc-prim:GHC.Types.I# 5)) Done: (\main:Demo.unusedarg -> (ghc-prim:GHC.Types.I# 5)) Done: (\main:Demo.unusedarg -> (ghc-prim:GHC.Types.I# 5))
Which results in a runtime type error:
prana: TypeError (NotAnInstanceDictionary (Id {idStableName = "main:Demo.person", idUnique = Unique 8214565720323785170, idCategory = ValCat}) (LamWHNF (Id {idStableName = "main:Demo.unusedarg", idUnique = Unique 6989586621679011036, idCategory = ValCat}) (AppE (VarE (Id {idStableName = "ghc-prim:GHC.Types.I#", idUnique = Unique 3891110078048108563, idCategory = DataCat})) (LitE (Int 5)))))
I could ignore the fact that I got a function instead of a dictionary, and then evaluation proceeds OK:
Eval: ((main:Demo.person main:Demo.$fPersonX) main:Demo.X) Eval: (main:Demo.person main:Demo.$fPersonX) Eval: main:Demo.person Done: main:Demo.person[Method]0 Eval: main:Demo.$fPersonX Eval: main:Demo.$cperson Eval: main:Demo.$cperson Eval: (\main:Demo.unusedarg -> (ghc-prim:GHC.Types.I# 5)) Done: (\main:Demo.unusedarg -> (ghc-prim:GHC.Types.I# 5)) Done: (\main:Demo.unusedarg -> (ghc-prim:GHC.Types.I# 5)) Done: (\main:Demo.unusedarg -> (ghc-prim:GHC.Types.I# 5)) Done: (\main:Demo.unusedarg -> (ghc-prim:GHC.Types.I# 5)) Done: (\main:Demo.unusedarg -> (ghc-prim:GHC.Types.I# 5)) Eval: (ghc-prim:GHC.Types.I# 5) Eval: ghc-prim:GHC.Types.I# Done: (ghc-prim:GHC.Types.I#[Con] ) Done: (ghc-prim:GHC.Types.I#[Con] 5) Done: (ghc-prim:GHC.Types.I#[Con] 5) ConWHNF (Id {idStableName = "ghc-prim:GHC.Types.I#", idUnique = Unique 3891110078048108563, idCategory = DataCat}) [LitE (Int 5)]
But this feels a bit less structured. I want, for example, to be able to update definitions at runtime, so runtime type-errors will be a thing sometimes. I feel like this kind of thing would make some confusing runtime type errors. And what other class-specific oddities should I have to handle?
I haven't gotten to dictionaries with superclasses yet, that'll require more handling so I'll probably need more knowledge of classes anyway.
So I'm wondering whether at the STG phase all classes have been abstracted away and we really do only deal with lambdas, lets and cases? I didn't see any class-specific code in your project.
I only chose Core because I wanted to stay as close to the original Haskell source as possible, and have a very simple evaluation model, but perhaps STG is the easier choice.
Cheers On Sat, 1 Dec 2018 at 12:42, Csaba Hruska
wrote: The package name + module name is always unique in every Haskell
program, module names can not be duplicated in a package and package names are unique also.
There are 2 kinds of identifiers, local and exported. You can construct a whole program unique name for:
exported identifier with combining the package name + module name + occurence name (without the unique value) local identifier with combining the package name + module name + occurence name + unique (what is unique per invocation)
It is safe because only the exported names can appear in an external expression and those do not contain the GHC's unique value. Just think about how the object code linker deals with GHC symbols.
Cheers, Csaba
On Sat, Dec 1, 2018 at 1:23 PM Christopher Done
wrote: I think what Csaba means is that we can have e.g.
* GHC invocation 1 * ghc-prim: * MyModule.foo has Unique 123 * OtherModule.bar has Unique 124 * GHC invocation 2 * base: * MyMod.mu has Unique 123 * OtherMod.zot has Unique 124
For a unique reference then, we just need:
* ghc-prim:MyMobile.foo+123 * ghc-prim:OtherModule.bar+124 * base:MyMod.mu+123 * base:OtherMod.zot+124
For any local lookup this is reliable. If the lookup fails, a lookup without the Unique works for cross-module lookups.