packages feed

uhc-light-1.1.9.2: src/UHC/Light/Compiler/Ty/Trf/BetaReduce.hs

module UHC.Light.Compiler.Ty.Trf.BetaReduce
( TyBetaRedOut, mkDfltTyBetaRedOut, TyBetaRedOut' (..)
, emptyTyBetaRedOut', emptyTyBetaRedOut
, betaRedIsOkFitsinCombi
, TyBetaRedLkup, betaRedTyLookup
, tyBetaRed, tyBetaRedAndInit
, tyBetaRedFullMb
, tyBetaRedFull )
where
import UHC.Light.Compiler.Base.HsName.Builtin
import UHC.Light.Compiler.Base.Common
import UHC.Light.Compiler.Base.TermLike
import UHC.Light.Compiler.Opts
import UHC.Light.Compiler.Ty.FitsInCommon
import UHC.Light.Compiler.Ty.FitsInCommon2
import UHC.Light.Compiler.Ty
import UHC.Light.Compiler.Gam.Full
import UHC.Light.Compiler.Substitutable
import UHC.Light.Compiler.VarMp
import Data.Maybe
import UHC.Util.Pretty

{-# LINE 34 "src/ehc/Ty/Trf/BetaReduce.chs" #-}
data TyBetaRedOut' x
  = TyBetaRedOut
      { tbroutRes			:: x
      , tbroutVarMp			:: VarMp
      , tbroutTracePPL		:: [PP_Doc]
      , tbroutExpandedTo	:: Maybe TyBetaRedLookAheadExpansion	-- 1 expansion step lookahead type function + args
      }

type TyBetaRedOut    = TyBetaRedOut' Ty

mkDfltTyBetaRedOut :: x -> TyBetaRedOut' x
mkDfltTyBetaRedOut = emptyTyBetaRedOut'

{-# LINE 49 "src/ehc/Ty/Trf/BetaReduce.chs" #-}
emptyTyBetaRedOut' :: x -> TyBetaRedOut' x
emptyTyBetaRedOut' x = TyBetaRedOut x emptyVarMp [] Nothing

emptyTyBetaRedOut :: TyBetaRedOut' Ty
emptyTyBetaRedOut = emptyTyBetaRedOut' Ty_Any

{-# LINE 61 "src/ehc/Ty/Trf/BetaReduce.chs" #-}
-- | expansion lookahead info
type TyBetaRedLookAheadExpansion
  = ( Ty							-- type function
    , [Ty]							-- arguments
    , Maybe TyBetaRedOut			-- function in ty looked up as if it were to be used for expansion
    )


{-# LINE 74 "src/ehc/Ty/Trf/BetaReduce.chs" #-}
-- | check for a valid combi using lookahead info of next expansion.
--   Basically prevent synonyms and lambdas from being bound, but forced to be expanded
betaRedIsOkFitsinCombi :: (Ty -> Bool) -> TyBetaRedOut -> TyBetaRedOut -> Bool
betaRedIsOkFitsinCombi isBoundable
                       (TyBetaRedOut {tbroutExpandedTo = Just (fl,al,_    )})		-- a tvar
                       (TyBetaRedOut {tbroutExpandedTo = Just (fr,ar,mbExp)})		-- cannot be bound/matched against non expanded synonym/lambda
                       | isBoundable fl && not (null ar || null al) && (tyIsLam fr || isJust mbExp)
                       = False
{-
betaRedIsOkFitsinCombi isBoundable
                       (TyBetaRedExtra {tybetaredextraExpandedTo = Just (fl,al,mbExp)})
                       (TyBetaRedExtra {tybetaredextraExpandedTo = Just (fr,ar,_    )})
                       | isBoundable fr && not (null ar || null al) && (tyIsLam fl || isJust mbExp)
                       = False
-}
betaRedIsOkFitsinCombi _ _ _
                       = True

{-# LINE 98 "src/ehc/Ty/Trf/BetaReduce.chs" #-}
type TyBetaRedLkup gm = TyBetaRedEnv gm -> HsName -> Maybe TyBetaRedOut

betaRedTyLookup :: TyBetaRedLkup gm
betaRedTyLookup fi nm = fmap (mkDfltTyBetaRedOut . tgiTy) $ tyGamLookup nm $ feTyGam $ fiEnv $ tbredFI fi

{-# LINE 105 "src/ehc/Ty/Trf/BetaReduce.chs" #-}
-- | lookup the type used as if in function position of type application
betaRedTyFunLookup :: TyBetaRedEnv gm -> TyBetaRedLkup gm -> Ty -> Maybe TyBetaRedOut
betaRedTyFunLookup fi lkup funTy
  = do nm <- tyMbCon funTy
       t' <- lkup fi nm
       case tbroutRes t' of
          Ty_Con nm' | nm == nm' -> Nothing
          f                      -> Just (mkDfltTyBetaRedOut f)

{-# LINE 116 "src/ehc/Ty/Trf/BetaReduce.chs" #-}
-- | get the lookahead for reduction
betaRedTyLookAhead :: VarLookup gm TyVarId VarMpInfo => TyBetaRedEnv gm -> TyBetaRedLkup gm -> Ty -> TyBetaRedLookAheadExpansion
betaRedTyLookAhead renv lkup ty
  = unpack ty
  where unpack t = (f', as, betaRedTyFunLookup renv lkup f')
          where (f,as) = tyAppFunArgsWithLkup (fiLookupTyVarCyc fi) t
                f' = tyUnAnn $ fiLookupReplaceTyCyc fi f
                fi = tbredFI renv

{-# LINE 127 "src/ehc/Ty/Trf/BetaReduce.chs" #-}
-- | one expansion step of type level beta reduction
tyBetaRed1
  :: (VarLookup gm TyVarId VarMpInfo, VarLookupCmb VarMp gm, SubstVarKey gm ~ VarId, SubstVarVal gm ~ VarMpInfo)
     => TyBetaRedEnv gm -> TyBetaRedLkup gm -> Either Ty TyBetaRedLookAheadExpansion
     -> Maybe TyBetaRedOut
tyBetaRed1 renv lkup tyOrFunAndArgs
  = eval (either (betaRedTyLookAhead renv lkup) id tyOrFunAndArgs)
  where -- lambda expression: take body and substitute arguments
        eval (lam@(Ty_Lam fa b), args, f)
          | isJust mbEtaRed
              = mkres (appTopApp (fromJust mbEtaRed : args))
          | lamLen <= argLen
              = mkres (appTopApp (subst `varUpd` lamBody : drop lamLen args))
          | otherwise
              = Nothing
          where mbEtaRed = tyLamEtaRed lam
                (lamArgs,lamBody) = tyLamArgsRes lam
                lamLen = length lamArgs
                argLen = length args
                subst  = assocTyLToVarMp (zip lamArgs args)
        -- normalization for polarity types
        -- * removes double negations
        -- * removes negation on 'basic' polarities
        eval (Ty_Con nm, [arg], _)
          | nm == hsnPolNegation
              = case tyUnAnn $ fiLookupReplaceTyCyc fi fun' of
                  Ty_Con nm
                    | nm == hsnPolNegation   -> mkres (head args')
                    | otherwise              -> mkres (polOpp arg)
                  _ -> Nothing
              where
                (fun',args') = tyAppFunArgsWithLkup (fiLookupTyVarCyc fi) arg

        -- looked up in the environment
        eval (_, args, Just funExp)
              = mkres $ appTopApp $ tbroutRes funExp : args

        -- no expansion possible
        eval _ = Nothing

        -- utils
        mkres t  = Just ( (emptyTyBetaRedOut' t)
                            { tbroutExpandedTo = Just $ betaRedTyLookAhead renv lkup t
                            , tbroutTracePPL   = [trfitIn "tylam" ("from:" >#< ppTyWithFI fi (pack tyOrFunAndArgs) >-< "to  :" >#< ppTyWithFI fi t)]
                            }
                        )
        pack = either id (\(f,as,_) -> appTopApp (f:as))
        fi = tbredFI renv

{-# LINE 180 "src/ehc/Ty/Trf/BetaReduce.chs" #-}
tyBetaRed'
  :: (VarLookup gm TyVarId VarMpInfo, VarLookupCmb VarMp gm, SubstVarKey gm ~ VarId, SubstVarVal gm ~ VarMpInfo)
     => TyBetaRedEnv gm -> TyBetaRedLkup gm -> Either Ty TyBetaRedLookAheadExpansion
     -> [TyBetaRedOut]
tyBetaRed' renv lkup tyOrFunArgs
  = case tyBetaRed1 renv lkup tyOrFunArgs of
      Just re -> re : tyBetaRed' renv lkup (maybe (Left (tbroutRes re)) Right $ tbroutExpandedTo re)
      _       -> []

tyBetaRed
  :: (VarLookup gm TyVarId VarMpInfo, VarLookupCmb VarMp gm, SubstVarKey gm ~ VarId, SubstVarVal gm ~ VarMpInfo)
     => TyBetaRedEnv gm -> TyBetaRedLkup gm -> Ty
     -> [TyBetaRedOut]
tyBetaRed renv lkup ty = tyBetaRed' renv lkup (Left ty)

tyBetaRedAndInit
  :: (VarLookup gm TyVarId VarMpInfo, VarLookupCmb VarMp gm, SubstVarKey gm ~ VarId, SubstVarVal gm ~ VarMpInfo)
     => TyBetaRedEnv gm -> TyBetaRedLkup gm -> Ty
     -> [TyBetaRedOut]
tyBetaRedAndInit renv lkup ty
  = ((emptyTyBetaRedOut' ty) {tbroutExpandedTo = Just l}) : tyBetaRed' renv lkup (Right l)
  where l = betaRedTyLookAhead renv lkup ty

{-# LINE 210 "src/ehc/Ty/Trf/BetaReduce.chs" #-}
tyBetaRedFullMb
  :: (VarLookup gm TyVarId VarMpInfo, VarLookupCmb VarMp gm, SubstVarKey gm ~ VarId, SubstVarVal gm ~ VarMpInfo)
     => TyBetaRedEnv gm -> TyBetaRedLkup gm -> (Ty -> Maybe TyBetaRedOut) -> Ty
     -> Maybe TyBetaRedOut
tyBetaRedFullMb renv lkup redSub ty
  = fmap reda $ choose ty $ redl ty
  where env = fiEnv $ tbredFI renv
        lim     = ehcOptTyBetaRedCutOffAt $ feEHCOpts env
        redl ty = take lim $ tyBetaRed renv lkup ty
        reda re = if null (catMaybes as')
                  then mkDfltTyBetaRedOut ty
                  else let as'' = zipWith (\t mt -> maybe (mkDfltTyBetaRedOut t) id mt) as as'
                       in   emptyTyBetaRedOut {tbroutRes = mk f $ map tbroutRes as'', tbroutVarMp = varmpUnions $ map tbroutVarMp as''}
                where (f,as,mk) = tyDecomposeMk ty
                      as' = map redSub as
                      ty  = tbroutRes re
        choose a [] = Nothing
        choose a as = Just (last as)

{-# LINE 233 "src/ehc/Ty/Trf/BetaReduce.chs" #-}
tyBetaRedFull
  :: (VarLookup gm TyVarId VarMpInfo, VarLookupCmb VarMp gm)
     => TyBetaRedEnv gm -> VarMp -> Ty
     -> Ty
tyBetaRedFull renv varmp ty
  = maybe ty tbroutRes $ sub ty
  where fi  = tbredFI renv
        fi' = fi {fiVarMp = varmp}
        sub = \t -> tyBetaRedFullMb (renv {tbredFI = fi'}) betaRedTyLookup sub $ varmp `varUpd` t