{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ViewPatterns #-}
module UntypedPlutusCore.Transform.ForceDelay
( forceDelay
) where
import PlutusCore.Builtin (BuiltinSemanticsVariant)
import PlutusCore.Default (DefaultFun (IfThenElse), DefaultUni)
import PlutusCore.MkPlc (mkIterApp)
import UntypedPlutusCore.Core
import UntypedPlutusCore.Purity (isPure, isWorkFree)
import UntypedPlutusCore.Transform.Simplifier
( SimplifierStage (ForceDelay)
, SimplifierT
, recordSimplification
)
import Control.Lens (transformOf)
import Control.Monad (guard)
import Data.Foldable as Foldable (foldl')
forceDelay
:: (uni ~ DefaultUni, fun ~ DefaultFun, Monad m)
=> BuiltinSemanticsVariant fun
-> Term name uni fun a
-> SimplifierT name uni fun a m (Term name uni fun a)
forceDelay :: forall (uni :: * -> *) fun (m :: * -> *) name a.
(uni ~ DefaultUni, fun ~ DefaultFun, Monad m) =>
BuiltinSemanticsVariant fun
-> Term name uni fun a
-> SimplifierT name uni fun a m (Term name uni fun a)
forceDelay BuiltinSemanticsVariant fun
semVar Term name uni fun a
term = do
let result :: Term name uni fun a
result = ASetter
(Term name uni fun a)
(Term name uni fun a)
(Term name uni fun a)
(Term name uni fun a)
-> (Term name uni fun a -> Term name uni fun a)
-> Term name uni fun a
-> Term name uni fun a
forall a b. ASetter a b a b -> (b -> b) -> a -> b
transformOf ASetter
(Term name uni fun a)
(Term name uni fun a)
(Term name uni fun a)
(Term name uni fun a)
forall name (uni :: * -> *) fun ann (f :: * -> *).
Applicative f =>
(Term name uni fun ann -> f (Term name uni fun ann))
-> Term name uni fun ann -> f (Term name uni fun ann)
termSubterms (BuiltinSemanticsVariant fun
-> Term name uni fun a -> Term name uni fun a
forall (uni :: * -> *) fun name a.
(uni ~ DefaultUni, fun ~ DefaultFun) =>
BuiltinSemanticsVariant fun
-> Term name uni fun a -> Term name uni fun a
processTerm BuiltinSemanticsVariant fun
semVar) Term name uni fun a
term
Term name uni fun a
-> SimplifierStage
-> Term name uni fun a
-> SimplifierT name uni fun a m ()
forall (m :: * -> *) name (uni :: * -> *) fun a.
Monad m =>
Term name uni fun a
-> SimplifierStage
-> Term name uni fun a
-> SimplifierT name uni fun a m ()
recordSimplification Term name uni fun a
term SimplifierStage
ForceDelay Term name uni fun a
result
Term name uni fun a
-> SimplifierT name uni fun a m (Term name uni fun a)
forall a. a -> SimplifierT name uni fun a m a
forall (m :: * -> *) a. Monad m => a -> m a
return Term name uni fun a
result
processTerm
:: (uni ~ DefaultUni, fun ~ DefaultFun)
=> BuiltinSemanticsVariant fun -> Term name uni fun a -> Term name uni fun a
processTerm :: forall (uni :: * -> *) fun name a.
(uni ~ DefaultUni, fun ~ DefaultFun) =>
BuiltinSemanticsVariant fun
-> Term name uni fun a -> Term name uni fun a
processTerm BuiltinSemanticsVariant fun
semVar = \case
Force a
_ (Delay a
_ Term name uni fun a
t) -> Term name uni fun a
t
Force
a
_
( Term name uni fun a
-> (Term name uni fun a, [(a, Term name uni fun a)])
forall name (uni :: * -> *) fun a.
Term name uni fun a
-> (Term name uni fun a, [(a, Term name uni fun a)])
splitApplication ->
( forceIfThenElse :: Term name uni fun a
forceIfThenElse@(Force a
_ (Builtin a
_ fun
DefaultFun
IfThenElse))
, [(a, Term name uni fun a)
cond, (a
trueAnn, (Delay a
_ Term name uni fun a
trueAlt)), (a
falseAnn, (Delay a
_ Term name uni fun a
falseAlt))]
)
)
| (Term name uni fun a -> Bool) -> [Term name uni fun a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (\Term name uni fun a
alt -> BuiltinSemanticsVariant fun -> Term name uni fun a -> Bool
forall (uni :: * -> *) fun name a.
ToBuiltinMeaning uni fun =>
BuiltinSemanticsVariant fun -> Term name uni fun a -> Bool
isPure BuiltinSemanticsVariant fun
semVar Term name uni fun a
alt Bool -> Bool -> Bool
&& BuiltinSemanticsVariant fun -> Term name uni fun a -> Bool
forall (uni :: * -> *) fun name a.
ToBuiltinMeaning uni fun =>
BuiltinSemanticsVariant fun -> Term name uni fun a -> Bool
isWorkFree BuiltinSemanticsVariant fun
semVar Term name uni fun a
alt) [Term name uni fun a
trueAlt, Term name uni fun a
falseAlt] ->
Term name uni fun a
-> [(a, Term name uni fun a)] -> Term name uni fun a
forall (term :: * -> *) tyname name (uni :: * -> *) fun ann.
TermLike term tyname name uni fun =>
term ann -> [(ann, term ann)] -> term ann
mkIterApp
Term name uni fun a
forceIfThenElse
[(a, Term name uni fun a)
cond, (a
trueAnn, Term name uni fun a
trueAlt), (a
falseAnn, Term name uni fun a
falseAlt)]
original :: Term name uni fun a
original@(Force a
_ Term name uni fun a
subTerm) ->
case Term name uni fun a -> Maybe (Term name uni fun a)
forall name (uni :: * -> *) fun a.
Term name uni fun a -> Maybe (Term name uni fun a)
optimisationProcedure Term name uni fun a
subTerm of
Just Term name uni fun a
result -> Term name uni fun a
result
Maybe (Term name uni fun a)
Nothing -> Term name uni fun a
original
Term name uni fun a
t -> Term name uni fun a
t
optimisationProcedure :: Term name uni fun a -> Maybe (Term name uni fun a)
optimisationProcedure :: forall name (uni :: * -> *) fun a.
Term name uni fun a -> Maybe (Term name uni fun a)
optimisationProcedure Term name uni fun a
term = do
MultiApply name uni fun a
asMultiApply <- Term name uni fun a -> Maybe (MultiApply name uni fun a)
forall name (uni :: * -> *) fun a.
Term name uni fun a -> Maybe (MultiApply name uni fun a)
toMultiApply Term name uni fun a
term
MultiAbs name uni fun a
innerMultiAbs <- Term name uni fun a -> Maybe (MultiAbs name uni fun a)
forall name (uni :: * -> *) fun a.
Term name uni fun a -> Maybe (MultiAbs name uni fun a)
toMultiAbs (Term name uni fun a -> Maybe (MultiAbs name uni fun a))
-> (MultiApply name uni fun a -> Term name uni fun a)
-> MultiApply name uni fun a
-> Maybe (MultiAbs name uni fun a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MultiApply name uni fun a -> Term name uni fun a
forall name (uni :: * -> *) fun a.
MultiApply name uni fun a -> Term name uni fun a
appHead (MultiApply name uni fun a -> Maybe (MultiAbs name uni fun a))
-> MultiApply name uni fun a -> Maybe (MultiAbs name uni fun a)
forall a b. (a -> b) -> a -> b
$ MultiApply name uni fun a
asMultiApply
Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ [(a, Term name uni fun a)] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (MultiApply name uni fun a -> [(a, Term name uni fun a)]
forall name (uni :: * -> *) fun a.
MultiApply name uni fun a -> [(a, Term name uni fun a)]
appSpineRev MultiApply name uni fun a
asMultiApply) Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== [(a, name)] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (MultiAbs name uni fun a -> [(a, name)]
forall name (uni :: * -> *) fun a.
MultiAbs name uni fun a -> [(a, name)]
absVars MultiAbs name uni fun a
innerMultiAbs)
case MultiAbs name uni fun a -> Term name uni fun a
forall name (uni :: * -> *) fun a.
MultiAbs name uni fun a -> Term name uni fun a
absRhs MultiAbs name uni fun a
innerMultiAbs of
Delay a
_ Term name uni fun a
subTerm ->
let optimisedInnerMultiAbs :: MultiAbs name uni fun a
optimisedInnerMultiAbs = MultiAbs name uni fun a
innerMultiAbs {absRhs = subTerm}
optimisedMultiApply :: MultiApply name uni fun a
optimisedMultiApply =
MultiApply name uni fun a
asMultiApply {appHead = fromMultiAbs optimisedInnerMultiAbs}
in Term name uni fun a -> Maybe (Term name uni fun a)
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Term name uni fun a -> Maybe (Term name uni fun a))
-> (MultiApply name uni fun a -> Term name uni fun a)
-> MultiApply name uni fun a
-> Maybe (Term name uni fun a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MultiApply name uni fun a -> Term name uni fun a
forall name (uni :: * -> *) fun a.
MultiApply name uni fun a -> Term name uni fun a
fromMultiApply (MultiApply name uni fun a -> Maybe (Term name uni fun a))
-> MultiApply name uni fun a -> Maybe (Term name uni fun a)
forall a b. (a -> b) -> a -> b
$ MultiApply name uni fun a
optimisedMultiApply
Term name uni fun a
_ -> Maybe (Term name uni fun a)
forall a. Maybe a
Nothing
data MultiApply name uni fun a = MultiApply
{ forall name (uni :: * -> *) fun a.
MultiApply name uni fun a -> Term name uni fun a
appHead :: Term name uni fun a
, forall name (uni :: * -> *) fun a.
MultiApply name uni fun a -> [(a, Term name uni fun a)]
appSpineRev :: [(a, Term name uni fun a)]
}
toMultiApply :: Term name uni fun a -> Maybe (MultiApply name uni fun a)
toMultiApply :: forall name (uni :: * -> *) fun a.
Term name uni fun a -> Maybe (MultiApply name uni fun a)
toMultiApply Term name uni fun a
term =
case Term name uni fun a
term of
Apply a
_ Term name uni fun a
_ Term name uni fun a
_ -> [(a, Term name uni fun a)]
-> Term name uni fun a -> Maybe (MultiApply name uni fun a)
forall {f :: * -> *} {a} {name} {uni :: * -> *} {fun}.
Applicative f =>
[(a, Term name uni fun a)]
-> Term name uni fun a -> f (MultiApply name uni fun a)
run [] Term name uni fun a
term
Term name uni fun a
_ -> Maybe (MultiApply name uni fun a)
forall a. Maybe a
Nothing
where
run :: [(a, Term name uni fun a)]
-> Term name uni fun a -> f (MultiApply name uni fun a)
run [(a, Term name uni fun a)]
acc (Apply a
a Term name uni fun a
t1 Term name uni fun a
t2) =
[(a, Term name uni fun a)]
-> Term name uni fun a -> f (MultiApply name uni fun a)
run ((a
a, Term name uni fun a
t2) (a, Term name uni fun a)
-> [(a, Term name uni fun a)] -> [(a, Term name uni fun a)]
forall a. a -> [a] -> [a]
: [(a, Term name uni fun a)]
acc) Term name uni fun a
t1
run [(a, Term name uni fun a)]
acc Term name uni fun a
t =
MultiApply name uni fun a -> f (MultiApply name uni fun a)
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (MultiApply name uni fun a -> f (MultiApply name uni fun a))
-> MultiApply name uni fun a -> f (MultiApply name uni fun a)
forall a b. (a -> b) -> a -> b
$ Term name uni fun a
-> [(a, Term name uni fun a)] -> MultiApply name uni fun a
forall name (uni :: * -> *) fun a.
Term name uni fun a
-> [(a, Term name uni fun a)] -> MultiApply name uni fun a
MultiApply Term name uni fun a
t [(a, Term name uni fun a)]
acc
fromMultiApply :: MultiApply name uni fun a -> Term name uni fun a
fromMultiApply :: forall name (uni :: * -> *) fun a.
MultiApply name uni fun a -> Term name uni fun a
fromMultiApply (MultiApply Term name uni fun a
term [(a, Term name uni fun a)]
ts) =
(Term name uni fun a
-> (a, Term name uni fun a) -> Term name uni fun a)
-> Term name uni fun a
-> [(a, Term name uni fun a)]
-> Term name uni fun a
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
Foldable.foldl' (\Term name uni fun a
acc (a
ann, Term name uni fun a
arg) -> a
-> Term name uni fun a
-> Term name uni fun a
-> Term name uni fun a
forall name (uni :: * -> *) fun ann.
ann
-> Term name uni fun ann
-> Term name uni fun ann
-> Term name uni fun ann
Apply a
ann Term name uni fun a
acc Term name uni fun a
arg) Term name uni fun a
term [(a, Term name uni fun a)]
ts
data MultiAbs name uni fun a = MultiAbs
{ forall name (uni :: * -> *) fun a.
MultiAbs name uni fun a -> [(a, name)]
absVars :: [(a, name)]
, forall name (uni :: * -> *) fun a.
MultiAbs name uni fun a -> Term name uni fun a
absRhs :: Term name uni fun a
}
toMultiAbs :: Term name uni fun a -> Maybe (MultiAbs name uni fun a)
toMultiAbs :: forall name (uni :: * -> *) fun a.
Term name uni fun a -> Maybe (MultiAbs name uni fun a)
toMultiAbs Term name uni fun a
term =
case Term name uni fun a
term of
LamAbs a
_ name
_ Term name uni fun a
_ -> [(a, name)]
-> Term name uni fun a -> Maybe (MultiAbs name uni fun a)
forall {f :: * -> *} {a} {name} {uni :: * -> *} {fun}.
Applicative f =>
[(a, name)] -> Term name uni fun a -> f (MultiAbs name uni fun a)
run [] Term name uni fun a
term
Term name uni fun a
_ -> Maybe (MultiAbs name uni fun a)
forall a. Maybe a
Nothing
where
run :: [(a, name)] -> Term name uni fun a -> f (MultiAbs name uni fun a)
run [(a, name)]
acc (LamAbs a
a name
name Term name uni fun a
t) =
[(a, name)] -> Term name uni fun a -> f (MultiAbs name uni fun a)
run ((a
a, name
name) (a, name) -> [(a, name)] -> [(a, name)]
forall a. a -> [a] -> [a]
: [(a, name)]
acc) Term name uni fun a
t
run [(a, name)]
acc Term name uni fun a
t =
MultiAbs name uni fun a -> f (MultiAbs name uni fun a)
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (MultiAbs name uni fun a -> f (MultiAbs name uni fun a))
-> MultiAbs name uni fun a -> f (MultiAbs name uni fun a)
forall a b. (a -> b) -> a -> b
$ [(a, name)] -> Term name uni fun a -> MultiAbs name uni fun a
forall name (uni :: * -> *) fun a.
[(a, name)] -> Term name uni fun a -> MultiAbs name uni fun a
MultiAbs [(a, name)]
acc Term name uni fun a
t
fromMultiAbs :: MultiAbs name uni fun a -> Term name uni fun a
fromMultiAbs :: forall name (uni :: * -> *) fun a.
MultiAbs name uni fun a -> Term name uni fun a
fromMultiAbs (MultiAbs [(a, name)]
vars Term name uni fun a
term) =
(Term name uni fun a -> (a, name) -> Term name uni fun a)
-> Term name uni fun a -> [(a, name)] -> Term name uni fun a
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
Foldable.foldl' (\Term name uni fun a
acc (a
ann, name
name) -> a -> name -> Term name uni fun a -> Term name uni fun a
forall name (uni :: * -> *) fun ann.
ann -> name -> Term name uni fun ann -> Term name uni fun ann
LamAbs a
ann name
name Term name uni fun a
acc) Term name uni fun a
term [(a, name)]
vars