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