iu-parfunc / gibbon

A compiler for functional programs on serialized data
http://iu-parfunc.github.io/gibbon/
151 stars 13 forks source link

Support where expressions in Gibbon #209

Open vidsinghal opened 1 year ago

vidsinghal commented 1 year ago

Making an issue from discussion with @ckoparkar in the onboarding session. Gibbon doesn't support where expressions currently. Neither does it have a Where expression in L0-L4.

To get around this we can parse where expressions in the HaskellFront end, then write a L0 -> L0 compiler pass to transform a where expression to its equivalent Let expression which is supported in the language.

This is a good compiler pass to write for anyone who wants to get familiar with Gibbon internals.

f :: Int -> Int 
f a = y 
     where 
         x =  a * a
         y = x + 1  

equivalent let expression.

f' :: Int -> Int 
f' a = let 
           x = a * a 
           y = x + 1
         in y
ulysses4ever commented 5 months ago

Good first issue, indeed. Note, however, that in Haskell there are subtle differences between let and where, as discussed on the Haskell wiki: https://wiki.haskell.org/Let_vs._Where

For example, this is not easy to encode with let:

f x
  | cond1 x   = a
  | cond2 x   = g a
  | otherwise = f (h x a)
  where
    a = w x

But Gibbon doesn't seem to allow guards in function definitions. So, maybe the proposed desugaring into let's is viable.

ulysses4ever commented 5 months ago

Currently, the parser seems to simply be throwing away the wheres :-)

-- tmp.gibbon.hs
f x = y
  where
    y = x+1

gibbon_main = f 1
❯ $g --run ./tmp.gibbon.hs -v4
 ! Responding to env Var: GIBBON_DEBUG=4
 ! We set DEBUG based on command-line verbose arg: 4
 [compiler] pipeline starting, parsed program: 
================================================================================
Prog {ddefs = [],
      fundefs = [(f,
                  FunDef {funName = "f",
                          funArgs = [x],
                          funTy = ForAll [] (ArrowTy [MetaTv $0] (MetaTv $1)),
                          funBody = VarE "y",
                          funMeta = FunMeta {funRec = NotRec,
                                             funInline = NoInline,
                                             funCanTriggerGC = False}})],
      mainExp = Just (AppE "f" [] [LitE 1], MetaTv $2)}

 [compiler] Running pass, freshen
Pass output:
================================================================================
{meta: FunMeta {funRec = NotRec, funInline = NoInline, funCanTriggerGC = False}}
f :: forall. ($0 -> $1)
f x_3 =
    y

gibbon_main :: $2
gibbon_main = (f [] 1)

 [compiler] Running pass, typecheck
gibbon: L0.Typecheck: 
    Unbound variable y in Var "f"
CallStack (from HasCallStack):
  error, called at src/Gibbon/L0/Typecheck.hs:83:18 in gibbon-0.3-inplace:Gibbon.L0.Typecheck
ulysses4ever commented 4 months ago

The AST for where is currently being discarded at https://github.com/iu-parfunc/gibbon/blob/cde71dee2171b70f254e2c0ef5d558744080765c/gibbon-compiler/src/Gibbon/HaskellFrontend.hs#L884 Should be easy to fix it, but I was contemplating on how much work would #132 take (it'd require to re-do this transformation on another AST, ghc-lib-parser's one instead of haskell-src-ext's one).