packages feed

Annotations-0.2.1: tests/MultiRec/Expr.hs

{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE Rank2Types #-}

module MultiRec.Expr where

import Annotations.MultiRec.ShowFam
import Annotations.MultiRec.ErrorAlg

import Generics.MultiRec.Base


data Expr
  = EAdd     Expr  Expr
  | EMul     Expr  Expr
  | ETup     Expr  Expr
  | EIntLit  Int
  | ETyped   Expr  Type
  deriving (Eq, Show)

data Type
  = TyInt
  | TyTup  Type Type
  deriving (Eq, Show)


type PF_Expr =
       I  Expr  :*:  I  Expr  :*:  U
  :+:  I  Expr  :*:  I  Expr  :*:  U
  :+:  I  Expr  :*:  I  Expr  :*:  U
  :+:  K  Int   :*:  U
  :+:  I  Expr  :*:  I  Type  :*:  U

type PF_Type =
       U
  :+:  I  Type  :*:  I  Type  :*:  U

type instance PF Tuples = PF_Expr :>: Expr :+: PF_Type :>: Type

data Tuples :: * -> * where
  Expr  :: Tuples Expr
  Type  :: Tuples Type

instance EqS Tuples where
  eqS Expr Expr = Just Refl
  eqS Type Type = Just Refl
  eqS _    _    = Nothing

instance El Tuples Expr where
  proof = Expr

instance El Tuples Type where
  proof = Type

instance ShowFam Tuples where
  showFam Expr  = show
  showFam Type  = show

instance Fam Tuples where

  from Expr ex  = L . Tag $ case ex of
    EAdd x y     -> L              $ I (I0 x)  :*: I (I0 y)  :*: U
    EMul x y     -> R . L          $ I (I0 x)  :*: I (I0 y)  :*: U
    ETup x y     -> R . R . L      $ I (I0 x)  :*: I (I0 y)  :*: U
    EIntLit n    -> R . R . R . L  $ K n       :*: U
    ETyped e t   -> R . R . R . R  $ I (I0 e)  :*: I (I0 t)  :*: U
  from Type ty  = R . Tag $ case ty of
      TyInt      -> L              $ U
      TyTup x y  -> R              $ I (I0 x)  :*: I (I0 y)  :*: U

  to Expr (L (Tag ex))  = case ex of
    L           (I (I0 x) :*: I (I0 y) :*: U)     -> EAdd x y
    R (L        (I (I0 x) :*: I (I0 y) :*: U))    -> EMul x y
    R (R (L     (I (I0 x) :*: I (I0 y) :*: U)))   -> ETup x y
    R (R (R (L  (K n                   :*: U))))  -> EIntLit n
    R (R (R (R  (I (I0 x) :*: I (I0 y) :*: U))))  -> ETyped x y
  to Type (R (Tag ty))  = case ty of
    L           U                                 -> TyInt
    R           (I (I0 x) :*: I (I0 y) :*: U)     -> TyTup x y

-- $(deriveConstructors [''Expr, ''Type])
-- $(deriveFamily ''AST [''Expr, ''Type] "PFAST")
-- type instance PF AST = PFAST

-- inferTypeExpr :: ErrorAlg (PF_Expr :>: Expr) String Type
-- inferTypeExpr = undefined & undefined & undefined & undefined & undefined
-- 
-- inferTypeType :: ErrorAlg (PF_Type :>: Type) String Type
-- inferTypeType = undefined & undefined
-- 
-- inferType :: ErrorAlg (PF_Tuples) String Type
-- inferType = inferTypeExpr & inferTypeType

-- inferType :: ErrorAlg (PF Tuples) String Type

type ExprErrorAlg e a
   =   (a     -> a     ->  Either e a)
  :&:  (a     -> a     ->  Either e a)
  :&:  (a     -> a     ->  Either e a)
  :&:  (Int            ->  Either e a)
  :&:  (a     -> a     ->  Either e a)

type TypeErrorAlg e a
   =                       Either e a
  :&:  (a     -> a     ->  Either e a)

-- inferType :: ExprErrorAlg String Type :&: TypeErrorAlg String Type
inferType :: ErrorAlg (PF Tuples) String Type
inferType = ( equal "+" & equal "*" & tup & const (Right TyInt) & equal "::" )
          & ( Right TyInt & tup )
  where
    equal op ty1 ty2
      | ty1 == ty2 = Right ty1
      | otherwise  = Left ("lhs and rhs of " ++ op ++ " must have equal types")
    tup ty1 ty2 = Right (TyTup ty1 ty2)

type (:&:) = (,)
infixr :&: