150PLD-Fall2019 / Exemplars

4 stars 1 forks source link

Better way to lift #39

Open MatthewDHarrison opened 4 years ago

MatthewDHarrison commented 4 years ago

I recall there being a better way to create lift functions for our own syntax by somehow deriving them, but I'm not sure how to do this - how do we derive lift functions for our syntax?

mpahrens commented 4 years ago

Yep! There is: 1) Add th-lift as a dependency to your package.yaml. E.g:


dependencies:
- base >= 4.7 && < 5
- containers
- parsec
- haskell-src-meta
- mtl
- transformers
- template-haskell
- th-lift

2) At the top of your file, add the DeriveLift to the language extensions. E.g:


{-# LANGUAGE TemplateHaskell, QuasiQuotes, DeriveLift #-}
module Main where

3) add Lift to the deriving macro on your data declarations. E.g:


data AST = Num Int
                 | Plus AST AST
                 ....
  deriving (Show, Eq, Lift)

4) Now you can splice in "lifted" values of this type at compile time:


myCodeGenerator :: AST -> Q Exp
myCodeGenerator ast = [| ast |]     -- practically useless, identity code generator
x = $(myCodeGenerator (Num 1)) -- compiles to: x = Num 1

Advanced Note: If your data type definition includes references to Types that do not have a Lift instance from th-lift, you can see if they are in th-lift-instances. Or, you can try to "stand alone" derive them