{-# 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