-- SPDX-FileCopyrightText: 2022 Oxhead Alpha
-- SPDX-License-Identifier: LicenseRef-MIT-OA

module Lorentz.Lambda
  ( WrappedLambda(..)
  , Lambda
  , mkLambda
  ) where

import Lorentz.Annotation
import Lorentz.Base
import Morley.AsRPC (HasRPCRepr(..))
import Morley.Michelson.Typed
import Morley.Michelson.Typed.Contract (giveNotInView)

-- | A helper type to construct Lorentz lambda values; Use this for lambda
-- values outside of Lorentz contracts or with @push@.
--
-- The primary reason this is a newtype and not a type synonym is to avoid
-- accidentally splicing the output of 'mkLambda' in-line.
newtype WrappedLambda i o = WrappedLambda {forall (i :: [*]) (o :: [*]). WrappedLambda i o -> i :-> o
unWrappedLambda :: i :-> o}
  deriving stock (Int -> WrappedLambda i o -> ShowS
[WrappedLambda i o] -> ShowS
WrappedLambda i o -> String
(Int -> WrappedLambda i o -> ShowS)
-> (WrappedLambda i o -> String)
-> ([WrappedLambda i o] -> ShowS)
-> Show (WrappedLambda i o)
forall (i :: [*]) (o :: [*]). Int -> WrappedLambda i o -> ShowS
forall (i :: [*]) (o :: [*]). [WrappedLambda i o] -> ShowS
forall (i :: [*]) (o :: [*]). WrappedLambda i o -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [WrappedLambda i o] -> ShowS
$cshowList :: forall (i :: [*]) (o :: [*]). [WrappedLambda i o] -> ShowS
show :: WrappedLambda i o -> String
$cshow :: forall (i :: [*]) (o :: [*]). WrappedLambda i o -> String
showsPrec :: Int -> WrappedLambda i o -> ShowS
$cshowsPrec :: forall (i :: [*]) (o :: [*]). Int -> WrappedLambda i o -> ShowS
Show, WrappedLambda i o -> WrappedLambda i o -> Bool
(WrappedLambda i o -> WrappedLambda i o -> Bool)
-> (WrappedLambda i o -> WrappedLambda i o -> Bool)
-> Eq (WrappedLambda i o)
forall (i :: [*]) (o :: [*]).
WrappedLambda i o -> WrappedLambda i o -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: WrappedLambda i o -> WrappedLambda i o -> Bool
$c/= :: forall (i :: [*]) (o :: [*]).
WrappedLambda i o -> WrappedLambda i o -> Bool
== :: WrappedLambda i o -> WrappedLambda i o -> Bool
$c== :: forall (i :: [*]) (o :: [*]).
WrappedLambda i o -> WrappedLambda i o -> Bool
Eq, (forall x. WrappedLambda i o -> Rep (WrappedLambda i o) x)
-> (forall x. Rep (WrappedLambda i o) x -> WrappedLambda i o)
-> Generic (WrappedLambda i o)
forall (i :: [*]) (o :: [*]) x.
Rep (WrappedLambda i o) x -> WrappedLambda i o
forall (i :: [*]) (o :: [*]) x.
WrappedLambda i o -> Rep (WrappedLambda i o) x
forall x. Rep (WrappedLambda i o) x -> WrappedLambda i o
forall x. WrappedLambda i o -> Rep (WrappedLambda i o) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall (i :: [*]) (o :: [*]) x.
Rep (WrappedLambda i o) x -> WrappedLambda i o
$cfrom :: forall (i :: [*]) (o :: [*]) x.
WrappedLambda i o -> Rep (WrappedLambda i o) x
Generic)
  deriving newtype ((forall (i :: [*]) (o :: [*]). (i :-> o) -> i :-> o)
 -> WrappedLambda i o -> WrappedLambda i o)
-> MapLorentzInstr (WrappedLambda i o)
(forall (i :: [*]) (o :: [*]). (i :-> o) -> i :-> o)
-> WrappedLambda i o -> WrappedLambda i o
forall (i :: [*]) (o :: [*]).
(forall (i :: [*]) (o :: [*]). (i :-> o) -> i :-> o)
-> WrappedLambda i o -> WrappedLambda i o
forall instr.
((forall (i :: [*]) (o :: [*]). (i :-> o) -> i :-> o)
 -> instr -> instr)
-> MapLorentzInstr instr
mapLorentzInstr :: (forall (i :: [*]) (o :: [*]). (i :-> o) -> i :-> o)
-> WrappedLambda i o -> WrappedLambda i o
$cmapLorentzInstr :: forall (i :: [*]) (o :: [*]).
(forall (i :: [*]) (o :: [*]). (i :-> o) -> i :-> o)
-> WrappedLambda i o -> WrappedLambda i o
MapLorentzInstr

deriving newtype instance IsoValue (a :-> b) => IsoValue (WrappedLambda a b)
deriving newtype instance HasAnnotation (i :-> o) => HasAnnotation (WrappedLambda i o)
deriving newtype instance HasRPCRepr (i :-> o) => HasRPCRepr (WrappedLambda i o)

-- | A constructor providing the required constraint for 'WrappedLambda'. This is
-- the only way to construct a lambda that uses operations forbidden in views.
mkLambda :: (IsNotInView => i :-> o) -> WrappedLambda i o
mkLambda :: forall (i :: [*]) (o :: [*]).
(IsNotInView => i :-> o) -> WrappedLambda i o
mkLambda IsNotInView => i :-> o
i = (i :-> o) -> WrappedLambda i o
forall (i :: [*]) (o :: [*]). (i :-> o) -> WrappedLambda i o
WrappedLambda ((i :-> o) -> WrappedLambda i o) -> (i :-> o) -> WrappedLambda i o
forall a b. (a -> b) -> a -> b
$ (IsNotInView => i :-> o) -> i :-> o
forall r. (IsNotInView => r) -> r
giveNotInView IsNotInView => i :-> o
i

-- | A type synonym representing Michelson lambdas.
type Lambda i o = WrappedLambda '[i] '[o]