packages feed

boltzmann-brain-1.6: Data/Boltzmann/Compiler/Haskell/Helpers.hs

{-|
 Module      : Data.Boltzmann.Compiler.Haskell.Helpers
 Description : Helper methods for GHC syntax.
 Copyright   : (c) Maciej Bendkowski, 2017-2019

 License     : BSD3
 Maintainer  : maciej.bendkowski@tcs.uj.edu.pl
 Stability   : experimental

 General utilities used across system compilers.
 -}
module Data.Boltzmann.Compiler.Haskell.Helpers where

import Language.Haskell.Exts hiding (List)

import Data.Boltzmann.System

-- | Prepares a system/module note.
systemNote :: PSystem Double -> String -> [String]
systemNote psys t = ["-- | System:       " ++ p,
                     "-- | System type:  " ++ t,
                     "-- | Stability:    experimental"]

    where sys = system psys
          p   = "(Types: " ++ show n ++ ", Constr: " ++ show m ++ ")"
          m   = constructors sys
          n   = size sys

unname :: String -> QName ()
unname = UnQual () . Ident ()

typeCons :: String -> Type ()
typeCons = TyCon () . unname

typeVar :: String -> Type ()
typeVar = TyVar () . Ident ()

varExp :: String -> Exp ()
varExp = Var () . unname

qVarExp :: String -> String -> Exp ()
qVarExp m s = Var () $ Qual () (ModuleName () m) (Ident () s)

conExp :: String -> Exp ()
conExp = Con () . unname

spliceExp :: Exp () -> Exp ()
spliceExp = SpliceExp () . ParenSplice ()

toLit :: Int -> Exp ()
toLit n = Lit () (Int () (toInteger n) (show n))

importType :: String -> ImportSpec ()
importType = IThingAll () . Ident ()

importType' :: String -> ImportSpec ()
importType' = IAbs () (NoNamespace ()). Ident ()

importFunc :: String -> ImportSpec ()
importFunc = IVar () . Ident ()

-- | Simple import declaration.
importFrom :: String -> [ImportSpec ()] -> ImportDecl ()
importFrom module' specs =
  ImportDecl { importAnn = ()
             , importModule    = ModuleName () module'
             , importQualified = False
             , importSrc       = False
             , importSafe      = False
             , importPkg       = Nothing
             , importAs        = Nothing
             , importSpecs     = Just $ ImportSpecList () False specs
             }

importQual :: String -> String -> ImportDecl ()
importQual module' synonym =
  ImportDecl { importAnn       = ()
             , importModule    = ModuleName () module'
             , importQualified = True
             , importSrc       = False
             , importSafe      = False
             , importPkg       = Nothing
             , importAs        = Just (ModuleName () synonym)
             , importSpecs     = Nothing
             }

exportType :: String -> ExportSpec ()
exportType s = EThingWith () (NoWildcard ()) (unname s) []

exportTypes :: PSystem Double -> [ExportSpec ()]
exportTypes sys = map exportType $ typeList sys

exportFunc :: String -> ExportSpec ()
exportFunc = EVar () . unname

-- | Simple function declaration.
declTFun :: String -> Type () -> [String] -> Exp () -> [Decl ()]
declTFun f type' args' body = [decl, FunBind () [main]]
    where decl   = TypeSig () [Ident () f] type'
          args'' = map (PVar () . Ident ()) args'
          main   = Match () (Ident () f) args'' (UnGuardedRhs () body) Nothing

symbol :: String -> QOp ()
symbol s = QVarOp () $ UnQual () (Symbol () s)

greater :: Exp () -> Exp () -> Exp ()
greater x = InfixApp () x (symbol ">")

less :: Exp () -> Exp () -> Exp ()
less x = InfixApp () x (symbol "<")

and :: Exp () -> Exp () -> Exp ()
and x = InfixApp () x (symbol "&&")

lessEq :: Exp () -> Exp () -> Exp ()
lessEq x = InfixApp () x (symbol "<=")

toDouble :: Double -> Exp ()
toDouble x = Lit () $ Frac () (toRational x) (show (toRational x))

toString :: String -> Exp ()
toString s = Lit () $ String () s s

lessF :: Real a => Exp () -> a -> Exp ()
lessF v x = less v (Lit () (Frac () (toRational x) (show (toRational x))))

bind :: String -> Exp () -> Stmt ()
bind v = Generator () (PVar () $ Ident () v)

bindP :: String -> String -> Exp () -> Stmt ()
bindP x y = Generator ()
    (PTuple () Boxed [PVar () (Ident () x), PVar () (Ident () y)])

sub :: Exp () -> Exp () -> Exp ()
sub x (Lit () (Int () 0 "0")) = x
sub x y                       = InfixApp () x (symbol "-") y

add :: Exp () -> Exp () -> Exp ()
add x (Lit () (Int () 0 "0")) = x
add (Lit () (Int () 0 "0")) x = x
add x y                       = InfixApp () x (symbol "+") y

applyF :: Exp () -> [Exp ()] -> Exp ()
applyF = foldl (App ())

dot :: Exp () -> Exp () -> Exp ()
dot x = InfixApp () x (symbol ".")

declareADTs :: Bool -> PSystem a -> [Decl ()]
declareADTs withShow sys =
    map (declADT withShow) $ paramTypes sys

declADT :: Bool -> (String, [Cons a]) -> Decl ()
declADT withShow (t,[con]) = DataDecl () flag Nothing (DHead () (Ident () t))
                               [QualConDecl () Nothing Nothing (declCon con)]
                               [Deriving () Nothing [IRule () Nothing Nothing
                                    (IHCon () (unname "Show"))] | withShow]

   -- generate a newtype or data type?
   where flag = if length (args con) == 1 then NewType ()
                                          else DataType ()

declADT withShow (t,cons) = DataDecl () (DataType ()) Nothing (DHead () (Ident () t))
                               (map (QualConDecl () Nothing Nothing . declCon) cons)
                               [Deriving () Nothing [IRule () Nothing Nothing
                                    (IHCon () (unname "Show"))] | withShow]

declCon :: Cons a -> ConDecl ()
declCon expr = ConDecl () (Ident () $ func expr) ags
    where ags = map declArg (args expr)

declArg :: Arg -> Type ()
declArg (Type s) = typeVar s
declArg (List s) = TyList () $ typeVar s

caseAlt :: String -> Rhs () -> Alt ()
caseAlt n rhs =
    Alt () (PVar () $ Ident () n) rhs Nothing

caseAlt' :: Rhs () -> Alt ()
caseAlt' rhs =
    Alt () (PWildCard ()) rhs Nothing

caseInt :: String -> [(Int, Rhs () )] -> Exp ()
caseInt n xs = Case () (varExp n) (caseInt' xs)

caseInt' :: [(Int, Rhs ())] -> [Alt ()]
caseInt' [] = error "Absurd case"
caseInt' [(_,rhs)] = [caseAlt' rhs]
caseInt' ((n,rhs) : xs) = x : caseInt' xs
    where x = caseAlt (show n) rhs

-- Utils.
maybeT' :: Type ()
maybeT' = typeCons "MaybeT"

buffonMachine' :: Type ()
buffonMachine' = typeCons "BuffonMachine"

int' :: Type ()
int' = typeCons "Int"

g' :: Type ()
g' = typeVar "g"

randomGen' :: QName ()
randomGen' = unname "RandomGen"

return' :: Exp ()
return' = varExp "return"

double' :: Type ()
double' = typeCons "Double"

nat :: [String]
nat = map show ([0..] :: [Integer])

variableStream :: [String]
variableStream = map ('x' :) nat

weightStream :: [String]
weightStream = map ('w' :) nat

decisionTreeType :: Type ()
decisionTreeType = TyForall () Nothing Nothing
    (TyApp () (typeCons "DecisionTree")  int')

probList :: [(Cons Double, Int)] -> [Exp ()]
probList = map (\x -> Lit () (Frac () (f x) (show (f x))))
  where f = toRational . weight . fst

choiceN :: String -> Exp () -> Stmt ()
choiceN v s = bind v $ applyF (varExp "lift")
                [applyF (varExp "choice") [s]]