packages feed

lambda-cube-0.1.0.0: src/LambdaCube/SystemF/TypeChecker.hs

module LambdaCube.SystemF.TypeChecker where

import           Data.List              (uncons)
import           LambdaCube.SystemF.Ast

substituteType :: Int -> LCType -> LCTerm -> LCTerm
substituteType n v = go n
  where
    go _ e@(LCVar _)  = e
    go m (LCLam t b)  = LCLam (substituteTypeInType m v t) $ go m b
    go m (LCApp f a)  = go m f `LCApp` go m a
    go m (LCTLam b)   = LCTLam $ go (m + 1) b
    go m (LCTApp f t) = go m f `LCTApp` substituteTypeInType m v t

substituteTypeInType :: Int -> LCType -> LCType -> LCType
substituteTypeInType n v = go n
  where
    go _ LCBase       = LCBase
    go m e@(LCTVar l) = if m == l then v else e
    go m (LCArr a b)  = go m a `LCArr` go m b
    go m (LCUniv a)   = LCUniv $ go (m + 1) a

infer :: LCTerm -> Maybe LCType
infer = go []
  where
    go tl (LCVar n) = fmap fst . uncons $ drop n tl
    go tl (LCLam t b) = LCArr t <$> go (t : tl) b
    go tl (LCApp f a)
      | Just (LCArr at' rt) <- go tl f
      , Just at <- go tl a
      , at == at'
      = Just rt
      | otherwise
      = Nothing
    go tl (LCTLam b) = LCUniv <$> go tl b
    go tl (LCTApp f t)
      | Just (LCUniv rt) <- go tl f
      = Just $ substituteTypeInType 0 t rt
      | otherwise
      = Nothing