morley-1.2.0: src/Michelson/Typed/Extract.hs
-- | Module, containing functions to convert @Michelson.Untyped.Type@ to
-- @Michelson.Typed.T.T@ Michelson type representation (type stripped off all
-- annotations) and to @Michelson.Typed.Annotation.Notes@ value (which contains
-- field and type annotations for a given Michelson type).
--
-- I.e. @Michelson.Untyped.Type@ is split to value @t :: T@ and value of type
-- @Notes t@ for which @t@ is a type representation of value @t@.
module Michelson.Typed.Extract
( fromUType
, mkUType
, toUType
, withUType
, pattern AsUType
, pattern AsUTypeExt
) where
import Data.Singletons (Sing, SingI)
import Michelson.Typed.Annotation (Notes(..), notesSing)
import Michelson.Typed.Sing (SingT(..), fromSingT)
import Michelson.Typed.T (T(..), toUType)
import qualified Michelson.Untyped as Un
{-# ANN module ("HLint: ignore Avoid lambda using `infix`" :: Text) #-}
fromUType :: Un.Type -> T
fromUType ut = withUType ut (fromSingT . notesSing)
mkUType :: SingI x => Notes x -> Un.Type
mkUType notes = case (notesSing notes, notes) of
(STInt, NTInt tn) -> Un.Type Un.TInt tn
(STNat, NTNat tn) -> Un.Type Un.TNat tn
(STString, NTString tn) -> Un.Type Un.TString tn
(STBytes, NTBytes tn) -> Un.Type Un.TBytes tn
(STMutez, NTMutez tn) -> Un.Type Un.TMutez tn
(STBool, NTBool tn) -> Un.Type Un.TBool tn
(STKeyHash, NTKeyHash tn) -> Un.Type Un.TKeyHash tn
(STTimestamp, NTTimestamp tn) -> Un.Type Un.TTimestamp tn
(STAddress, NTAddress tn) -> Un.Type Un.TAddress tn
(STKey, NTKey tn) -> Un.Type Un.TKey tn
(STUnit, NTUnit tn) -> Un.Type Un.TUnit tn
(STSignature, NTSignature tn) -> Un.Type Un.TSignature tn
(STChainId, NTChainId tn) -> Un.Type Un.TChainId tn
(STOption _, NTOption tn n) -> Un.Type (Un.TOption (mkUType n)) tn
(STList _, NTList tn n) -> Un.Type (Un.TList (mkUType n)) tn
(STSet ct, NTSet tn n) -> Un.Type (Un.TSet $ mkComp ct n) tn
(STOperation, NTOperation tn) -> Un.Type Un.TOperation tn
(STContract _, NTContract tn n) ->
Un.Type (Un.TContract (mkUType n)) tn
(STPair _ _, NTPair tn fl fr nl nr) ->
Un.Type (Un.TPair fl fr (mkUType nl) (mkUType nr)) tn
(STOr _ _, NTOr tn fl fr nl nr) ->
Un.Type (Un.TOr fl fr (mkUType nl) (mkUType nr)) tn
(STLambda _ _, NTLambda tn np nq) ->
Un.Type (Un.TLambda (mkUType np) (mkUType nq)) tn
(STMap k _, NTMap tn nk nv) ->
Un.Type (Un.TMap (mkComp k nk) (mkUType nv)) tn
(STBigMap k _, NTBigMap tn nk nv) ->
Un.Type (Un.TBigMap (mkComp k nk) (mkUType nv)) tn
where
mkComp t a = Un.Type (Un.unwrapT $ toUType $ fromSingT t) a
-- | Convert 'Un.Type' to the isomorphic set of information from typed world.
withUType
:: Un.Type
-> (forall t. (Typeable t, SingI t) => Notes t -> r)
-> r
withUType (Un.Type ut tn) cont = case ut of
Un.TInt ->
cont (NTInt tn)
Un.TNat ->
cont (NTNat tn)
Un.TString ->
cont (NTString tn)
Un.TBytes ->
cont (NTBytes tn)
Un.TMutez ->
cont (NTMutez tn)
Un.TBool ->
cont (NTBool tn)
Un.TKeyHash ->
cont (NTKeyHash tn)
Un.TTimestamp ->
cont (NTTimestamp tn)
Un.TAddress ->
cont (NTAddress tn)
Un.TKey ->
cont (NTKey tn)
Un.TUnit ->
cont (NTUnit tn)
Un.TSignature ->
cont (NTSignature tn)
Un.TChainId ->
cont (NTChainId tn)
Un.TOption internalT -> withUType internalT $
\(notesInternalT :: Notes internalT) ->
cont (NTOption tn notesInternalT)
Un.TList listT -> withUType listT $
\(notesListT :: Notes listT) ->
cont (NTList tn notesListT)
Un.TSet (Un.Type sT nsCT) -> withUType (Un.Type sT Un.noAnn) $
\(_ :: Notes sCT) -> cont @('TSet sCT) (NTSet tn nsCT)
Un.TOperation ->
cont (NTOperation tn)
Un.TContract contractT -> withUType contractT $
\(notesContractT :: Notes contractT) ->
cont (NTContract tn notesContractT)
Un.TPair la ra lt rt ->
withUType lt $ \ln ->
withUType rt $ \rn ->
cont (NTPair tn la ra ln rn)
Un.TOr la ra lt rt ->
withUType lt $ \ln ->
withUType rt $ \rn ->
cont (NTOr tn la ra ln rn)
Un.TLambda lt rt ->
withUType lt $ \ln ->
withUType rt $ \rn ->
cont (NTLambda tn ln rn)
Un.TMap (Un.Type keyT notesT) valT ->
withUType (Un.Type keyT Un.noAnn) $ \(_ :: Notes keyT) ->
withUType valT $ \valN ->
cont @('TMap keyT _) (NTMap tn notesT valN)
Un.TBigMap (Un.Type keyT notesT) valT ->
withUType (Un.Type keyT Un.noAnn) $ \(_ :: Notes keyT) ->
withUType valT $ \valN ->
cont @('TBigMap keyT _) (NTBigMap tn notesT valN)
-- Helper datatype for 'AsUType'.
data SomeTypedInfo = forall t. (Typeable t, SingI t) => SomeTypedInfo (Notes t)
-- | Transparently represent untyped 'Type' as wrapper over @Notes t@
-- from typed world with @SingI t@ constraint.
--
-- As expression this carries logic of 'mkUType', and as pattern it performs
-- 'withUType' but may make code a bit cleaner.
--
-- Note about constraints: pattern signatures usually require two constraints -
-- one they require and another one which they provide. In our case we require
-- nothing (thus first constraint is @()@) and provide some knowledge about @t@.
pattern AsUType :: () => (Typeable t, SingI t) => Notes t -> Un.Type
pattern AsUType notes <- ((\ut -> withUType ut SomeTypedInfo) -> SomeTypedInfo notes)
where AsUType notes = mkUType notes
{-# COMPLETE AsUType #-}
-- | Similar to 'AsUType', but also gives 'Sing' for given type.
pattern AsUTypeExt :: () => (Typeable t, SingI t) => Sing t -> Notes t -> Un.Type
pattern AsUTypeExt sng notes <- AsUType notes@(notesSing -> sng)
where AsUTypeExt _ notes = AsUType notes
{-# COMPLETE AsUTypeExt #-}