{-# LANGUAGE LambdaCase   #-}
{-# LANGUAGE ViewPatterns #-}
module PlutusIR.Transform.Beta (
  beta
  ) where
import PlutusIR
import PlutusIR.Core.Type
import Control.Lens.Setter ((%~))
import Data.Function ((&))
import Data.List.NonEmpty qualified as NE
extractBindings :: Term tyname name uni fun a -> Maybe (NE.NonEmpty (Binding tyname name uni fun a), Term tyname name uni fun a)
 = [Term tyname name uni fun a]
-> Term tyname name uni fun a
-> Maybe
     (NonEmpty (Binding tyname name uni fun a),
      Term tyname name uni fun a)
forall tyname name (uni :: * -> *) fun ann.
[Term tyname name uni fun ann]
-> Term tyname name uni fun ann
-> Maybe
     (NonEmpty (Binding tyname name uni fun ann),
      Term tyname name uni fun ann)
collectArgs []
  where
      collectArgs :: [Term tyname name uni fun ann]
-> Term tyname name uni fun ann
-> Maybe
     (NonEmpty (Binding tyname name uni fun ann),
      Term tyname name uni fun ann)
collectArgs [Term tyname name uni fun ann]
argStack (Apply ann
_ Term tyname name uni fun ann
f Term tyname name uni fun ann
arg) = [Term tyname name uni fun ann]
-> Term tyname name uni fun ann
-> Maybe
     (NonEmpty (Binding tyname name uni fun ann),
      Term tyname name uni fun ann)
collectArgs (Term tyname name uni fun ann
argTerm tyname name uni fun ann
-> [Term tyname name uni fun ann] -> [Term tyname name uni fun ann]
forall a. a -> [a] -> [a]
:[Term tyname name uni fun ann]
argStack) Term tyname name uni fun ann
f
      collectArgs [Term tyname name uni fun ann]
argStack Term tyname name uni fun ann
t               = [Term tyname name uni fun ann]
-> [Binding tyname name uni fun ann]
-> Term tyname name uni fun ann
-> Maybe
     (NonEmpty (Binding tyname name uni fun ann),
      Term tyname name uni fun ann)
forall tyname name (uni :: * -> *) fun ann fun.
[Term tyname name uni fun ann]
-> [Binding tyname name uni fun ann]
-> Term tyname name uni fun ann
-> Maybe
     (NonEmpty (Binding tyname name uni fun ann),
      Term tyname name uni fun ann)
matchArgs [Term tyname name uni fun ann]
argStack [] Term tyname name uni fun ann
t
      matchArgs :: [Term tyname name uni fun ann]
-> [Binding tyname name uni fun ann]
-> Term tyname name uni fun ann
-> Maybe
     (NonEmpty (Binding tyname name uni fun ann),
      Term tyname name uni fun ann)
matchArgs (Term tyname name uni fun ann
arg:[Term tyname name uni fun ann]
rest) [Binding tyname name uni fun ann]
acc (LamAbs ann
a name
n Type tyname uni ann
ty Term tyname name uni fun ann
body) = [Term tyname name uni fun ann]
-> [Binding tyname name uni fun ann]
-> Term tyname name uni fun ann
-> Maybe
     (NonEmpty (Binding tyname name uni fun ann),
      Term tyname name uni fun ann)
matchArgs [Term tyname name uni fun ann]
rest (ann
-> Strictness
-> VarDecl tyname name uni fun ann
-> Term tyname name uni fun ann
-> Binding tyname name uni fun ann
forall tyname name (uni :: * -> *) fun a.
a
-> Strictness
-> VarDecl tyname name uni fun a
-> Term tyname name uni fun a
-> Binding tyname name uni fun a
TermBind ann
a Strictness
Strict (ann
-> name -> Type tyname uni ann -> VarDecl tyname name uni fun ann
forall k tyname name (uni :: * -> *) (fun :: k) ann.
ann
-> name -> Type tyname uni ann -> VarDecl tyname name uni fun ann
VarDecl ann
a name
n Type tyname uni ann
ty) Term tyname name uni fun ann
argBinding tyname name uni fun ann
-> [Binding tyname name uni fun ann]
-> [Binding tyname name uni fun ann]
forall a. a -> [a] -> [a]
:[Binding tyname name uni fun ann]
acc) Term tyname name uni fun ann
body
      matchArgs []         [Binding tyname name uni fun ann]
acc Term tyname name uni fun ann
t                    =
          case [Binding tyname name uni fun ann]
-> Maybe (NonEmpty (Binding tyname name uni fun ann))
forall a. [a] -> Maybe (NonEmpty a)
NE.nonEmpty ([Binding tyname name uni fun ann]
-> [Binding tyname name uni fun ann]
forall a. [a] -> [a]
reverse [Binding tyname name uni fun ann]
acc) of
              Maybe (NonEmpty (Binding tyname name uni fun ann))
Nothing   -> Maybe
  (NonEmpty (Binding tyname name uni fun ann),
   Term tyname name uni fun ann)
forall a. Maybe a
Nothing
              Just NonEmpty (Binding tyname name uni fun ann)
acc' -> (NonEmpty (Binding tyname name uni fun ann),
 Term tyname name uni fun ann)
-> Maybe
     (NonEmpty (Binding tyname name uni fun ann),
      Term tyname name uni fun ann)
forall a. a -> Maybe a
Just (NonEmpty (Binding tyname name uni fun ann)
acc', Term tyname name uni fun ann
t)
      matchArgs (Term tyname name uni fun ann
_:[Term tyname name uni fun ann]
_)      [Binding tyname name uni fun ann]
_   Term tyname name uni fun ann
_                    = Maybe
  (NonEmpty (Binding tyname name uni fun ann),
   Term tyname name uni fun ann)
forall a. Maybe a
Nothing
beta
    :: Term tyname name uni fun a
    -> Term tyname name uni fun a
beta :: Term tyname name uni fun a -> Term tyname name uni fun a
beta = \case
    
    
    (Term tyname name uni fun a
-> Maybe
     (NonEmpty (Binding tyname name uni fun a),
      Term tyname name uni fun a)
forall tyname name (uni :: * -> *) fun a.
Term tyname name uni fun a
-> Maybe
     (NonEmpty (Binding tyname name uni fun a),
      Term tyname name uni fun a)
extractBindings -> Just (NonEmpty (Binding tyname name uni fun a)
bs, Term tyname name uni fun a
t)) -> a
-> Recursivity
-> NonEmpty (Binding tyname name uni fun a)
-> Term tyname name uni fun a
-> Term tyname name uni fun a
forall tyname name (uni :: * -> *) fun a.
a
-> Recursivity
-> NonEmpty (Binding tyname name uni fun a)
-> Term tyname name uni fun a
-> Term tyname name uni fun a
Let (Term tyname name uni fun a -> a
forall tyname name (uni :: * -> *) fun a.
Term tyname name uni fun a -> a
termAnn Term tyname name uni fun a
t) Recursivity
NonRec NonEmpty (Binding tyname name uni fun a)
bs (Term tyname name uni fun a -> Term tyname name uni fun a
forall tyname name (uni :: * -> *) fun a.
Term tyname name uni fun a -> Term tyname name uni fun a
beta Term tyname name uni fun a
t)
    Term tyname name uni fun a
t                                 -> Term tyname name uni fun a
t Term tyname name uni fun a
-> (Term tyname name uni fun a -> Term tyname name uni fun a)
-> Term tyname name uni fun a
forall a b. a -> (a -> b) -> b
& (Term tyname name uni fun a
 -> Identity (Term tyname name uni fun a))
-> Term tyname name uni fun a
-> Identity (Term tyname name uni fun a)
forall tyname name (uni :: * -> *) fun a.
Traversal'
  (Term tyname name uni fun a) (Term tyname name uni fun a)
termSubterms ((Term tyname name uni fun a
  -> Identity (Term tyname name uni fun a))
 -> Term tyname name uni fun a
 -> Identity (Term tyname name uni fun a))
-> (Term tyname name uni fun a -> Term tyname name uni fun a)
-> Term tyname name uni fun a
-> Term tyname name uni fun a
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ Term tyname name uni fun a -> Term tyname name uni fun a
forall tyname name (uni :: * -> *) fun a.
Term tyname name uni fun a -> Term tyname name uni fun a
beta