compdata-dags-0.1: examples/Examples/TypeInference.hs
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ImplicitParams #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
module Examples.TypeInference where
import Data.Comp.AG
import Data.Comp.Dag
import qualified Data.Comp.Dag.AG as Dag
import Data.Comp.Term
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Comp.Derive
import System.IO.Unsafe
intersection :: (Ord k, Eq v) => Map k v -> Map k v -> Map k v
intersection = Map.mergeWithKey (\_ x1 x2 -> if x1 == x2 then Just x1 else Nothing)
(const Map.empty) (const Map.empty)
type Name = String
data Type = BoolType | IntType deriving (Eq, Show)
type Env = Map Name Type
insertEnv :: Name -> Maybe Type -> Env -> Env
insertEnv _ Nothing env = env
insertEnv v (Just t) env = Map.insert v t env
lookEnv :: Name -> Env -> Maybe Type
lookEnv = Map.lookup
data ExpF a = LitB Bool | LitI Int | Var Name
| Eq a a | Add a a | If a a a
| Iter Name a a a
deriving (Eq, Show, Functor, Foldable, Traversable)
$(derive [smartConstructors, makeShowF] [''ExpF])
typeOf :: (?below :: a -> atts, Maybe Type :< atts) =>
a -> Maybe Type
typeOf = below
typeInfS :: (Env :< atts) => Syn ExpF atts (Maybe Type)
typeInfS (LitB _) = Just BoolType
typeInfS (LitI _) = Just IntType
typeInfS (Eq a b)
| Just ta <- typeOf a
, Just tb <- typeOf b
, ta == tb = Just BoolType
typeInfS (Add a b)
| Just IntType <- typeOf a
, Just IntType <- typeOf b = Just IntType
typeInfS (If c t f)
| Just BoolType <- typeOf c
, Just tt <- typeOf t
, Just tf <- typeOf f
, tt == tf = Just tt
typeInfS (Var v) = lookEnv v above
typeInfS (Iter _ n i b)
| Just IntType <- typeOf n
, Just ti <- typeOf i
, Just tb <- typeOf b
, ti == tb = Just tb
typeInfS _ = Nothing
typeInfI :: (Maybe Type :< atts) => Inh ExpF atts Env
typeInfI (Iter v _ i b) = b |-> insertEnv v ti above
where ti = typeOf i
typeInfI _ = empty
typeInf :: Env -> Term ExpF -> Maybe Type
typeInf env = runAG typeInfS typeInfI (const env)
typeInfG :: Env -> Dag ExpF -> Maybe Type
typeInfG env = Dag.runAG intersection typeInfS typeInfI (const env)
gt1 :: Term ExpF
gt1 = iIter "x" x x (iAdd (iIter "y" z z (iAdd z y)) y)
where x = iLitI 10
y = iVar "x"
z = iLitI 5
g1 :: Dag ExpF
g1 = unsafePerformIO $ reifyDag gt1
-- [ (0, Iter "x" 1 1 2)
-- , (1, LitI 10)
-- , (2, Add 3 4)
-- , (3, Iter "y" 5 5 6)
-- , (4, Var "x")
-- , (5, LitI 5)
-- , (6, Add 5 4)
-- ]
typeTestG1 = typeInfG Map.empty g1
typeTestT1 = typeInf Map.empty (unravel g1)
gt2 :: Term ExpF
gt2 = iIter "x" x (iIter "x" x x y) y
where x = iLitI 0
y = iVar "x"
g2 :: Dag ExpF
g2 = unsafePerformIO $ reifyDag gt2
-- [ (0, Iter "x" 1 2 3)
-- , (1, LitI 0)
-- , (2, Iter "x" 1 1 3)
-- , (3, Var "x")
-- ]
typeTestG2 = typeInfG Map.empty g2
typeTestT2 = typeInf Map.empty (unravel g2)
gt3 :: Term ExpF
gt3 = iAdd (iIter "x" x x z) (iIter "x" y y z)
where x = iLitI 10
y = iLitB False
z = iVar "x"
g3 :: Dag ExpF
g3 = unsafePerformIO $ reifyDag gt3
-- [ (0, Add 1 3)
-- , (1, Iter "x" 2 2 5)
-- , (2, LitI 10)
-- , (3, Iter "x" 4 4 5)
-- , (4, LitB False)
-- , (5, Var "x")
-- ]
typeTestG3 = typeInfG Map.empty g3
typeTestT3 = typeInf Map.empty (unravel g3)