Jikka-5.2.0.0: src/Jikka/Core/Convert/Eta.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
-- |
-- Module : Jikka.Core.Convert.Eta
-- Description : does eta-reductions and makes exprs pointful. / eta 簡約を行って式を pointful にします。
-- Copyright : (c) Kimiyuki Onaka, 2021
-- License : Apache License 2.0
-- Maintainer : kimiyuki95@gmail.com
-- Stability : experimental
-- Portability : portable
module Jikka.Core.Convert.Eta
( run,
-- * internal rules
rule,
)
where
import Data.Maybe
import Jikka.Common.Alpha
import Jikka.Common.Error
import Jikka.Core.Language.BuiltinPatterns
import Jikka.Core.Language.Expr
import Jikka.Core.Language.Lint
import Jikka.Core.Language.RewriteRules
import Jikka.Core.Language.Util
expandExpr :: MonadAlpha m => Type -> Expr -> m (Maybe Expr)
expandExpr t e = case (t, e) of
(FunTy t1 t2, Lam x _ body) -> do
body <- expandExpr t2 body
return $ Lam x t1 <$> body
(FunTy t1 t2, e) -> do
x <- genVarName'
let e' = App e (Var x)
e'' <- expandExpr t2 e'
return . Just $ Lam x t1 (fromMaybe e' e'')
_ -> return Nothing
rule :: MonadAlpha m => RewriteRule m
rule =
let go :: MonadAlpha m => Expr -> Type -> (Expr -> Expr) -> m (Maybe Expr)
go e t f = (f <$>) <$> expandExpr t e
in makeRewriteRule "eta-reduction" $ \_ -> \case
Let x t e1 e2 -> go e1 t (\e1 -> Let x t e1 e2)
Iterate' t k f x -> go f (FunTy t t) (\f -> Iterate' t k f x)
Foldl' t1 t2 f init xs -> go f (FunTy t2 (FunTy t1 t1)) (\f -> Foldl' t1 t2 f init xs)
Scanl' t1 t2 f init xs -> go f (FunTy t2 (FunTy t1 t1)) (\f -> Scanl' t1 t2 f init xs)
Build' t f xs n -> go f (FunTy (ListTy t) t) (\f -> Build' t f xs n)
Map' t1 t2 f xs -> go f (FunTy t1 t2) (\f -> Map' t1 t2 f xs)
Filter' t f xs -> go f (FunTy t BoolTy) (\f -> Filter' t f xs)
_ -> return Nothing
runProgram :: (MonadAlpha m, MonadError Error m) => Program -> m Program
runProgram = applyRewriteRuleProgram' rule
-- `run` does eta-reductions in some locations.
-- This aims to:
-- * simplify other rewrite-rules
-- * convert to C++
-- TODO: expand in toplevel-let too.
--
-- == Examples
--
-- Before:
--
-- > foldl (+) 0 xs
--
-- After:
--
-- > foldl (fun y x -> y + x) 0 xs
run :: (MonadAlpha m, MonadError Error m) => Program -> m Program
run prog = wrapError' "Jikka.Core.Convert.Eta" $ do
precondition $ do
ensureWellTyped prog
prog <- runProgram prog
postcondition $ do
ensureWellTyped prog
return prog