Jikka-5.6.0.0: src/Jikka/Core/Language/Eta.hs
{-# LANGUAGE FlexibleContexts #-}
-- |
-- Module : Jikka.Core.Language.Eta
-- Description : does eta-reductions and eta-expansions. / eta 簡約および eta 展開を行います。
-- Copyright : (c) Kimiyuki Onaka, 2021
-- License : Apache License 2.0
-- Maintainer : kimiyuki95@gmail.com
-- Stability : experimental
-- Portability : portable
module Jikka.Core.Language.Eta
( etaExpand,
etaExpand',
etaReduce,
etaReduce',
)
where
import Control.Monad.Trans.Maybe
import Data.Maybe
import Jikka.Common.Alpha
import Jikka.Common.Error
import Jikka.Core.Language.Expr
import Jikka.Core.Language.FreeVars
import Jikka.Core.Language.TypeCheck
import Jikka.Core.Language.Util
etaExpand' :: (MonadAlpha m, MonadError Error m) => [(VarName, Type)] -> Expr -> m (Maybe Expr)
etaExpand' env e = runMaybeT $ do
t <- lift $ typecheckExpr env e
ts <- case uncurryFunTy t of
(ts@(_ : _), _) -> return ts
_ -> hoistMaybe Nothing
let (args, body) = uncurryLam e
guard $ length args /= length ts -- otherwise, it's already eta-expanded
args' <- forM (drop (length args) ts) $ \t -> do
x <- lift genVarName'
return (x, t)
return $ curryLam (args ++ args') (uncurryApp body (map (Var . fst) args'))
-- `etaExpand` does an eta-expansion.
--
-- == Examples
--
-- Before:
--
-- > map
--
-- After:
--
-- > fun f xs -> map f xs
--
-- Before:
--
-- > let f x y = x + y in f
--
-- After:
--
-- > fun x y -> (let f x y = x + y in f) x y
etaExpand :: (MonadAlpha m, MonadError Error m) => [(VarName, Type)] -> Expr -> m Expr
etaExpand env e = fromMaybe e <$> etaExpand' env e
etaReduce' :: Expr -> Maybe Expr
etaReduce' e = do
let (args, body) = uncurryLam e
let (f, args') = curryApp body
guard $ length args <= length args'
let k = length args' - length args
let f' = uncurryApp f (take k args')
let args'' = drop k args'
guard $ args'' == map (Var . fst) args
guard $ all (\(x, _) -> x `isUnusedVar` f') args
return f'
-- `etaReduce` does an eta-reduce in the result expr.
--
-- == Examples
--
-- Before:
--
-- > fun f xs -> map f xs
--
-- After:
--
-- > map
--
-- Before:
--
-- > fun x y -> (let f x y = x + y in f) x y
--
-- After:
--
-- > let f x y = x + y in f
etaReduce :: Expr -> Expr
etaReduce e = fromMaybe e (etaReduce' e)