imports
{-# OPTIONS_GHC -Wno-redundant-constraints #-}
{-# LANGUAGE UndecidableInstances #-}
module Plutarch.Docs.PlutusTypePConAndPMatch (PMyTypeData(..)) where
import Data.Kind (Type)
import GHC.Generics (Generic)
import Generics.SOP qualified as SOP
import Plutarch.Prelude
PlutusType
PlutusType is the primary typeclass that determines the underlying representation for a Plutarch type. It lets you construct and deconstruct Plutus Core constants from a Plutarch type's constructors
(possibly containing other Plutarch terms).
NOTE: It's essentially a combination of
PCon(for term construction) andPMatch(for term deconstruction). Nowadays,PConandPMatchare actually both just an alias forPlutusTypeand you'll get a deprecation warning if you use them.
class PlutusType (a :: S -> Type) where
{-
snip
-}
pcon' :: forall s. a s -> Term s (PInner a)
default pcon' :: DerivePlutusType a => forall s. a s -> Term s (PInner a)
pcon' = let _ = witness (Proxy @(PlutusType a)) in derivedPCon
pmatch' :: forall s b. Term s (PInner a) -> (a s -> Term s b) -> Term s b
default pmatch' :: DerivePlutusType a => forall s b. Term s (PInner a) -> (a s -> Term s b) -> Term s b
pmatch' = derivedPMatch
Note: You don't need to look too much into the types! After all, you'll be using
pconandpmatch, rather thanpcon'andpmatch'.PInneris meant to represent the "inner" type ofa- the Plutarch type representing the Plutus Core constant used to representa.
You should always use pcon and pmatch instead of pcon' and pmatch' - these are provided by the PCon and PMatch typeclasses:
Another feature of PlutusType instances is that you can extract out the inner type of any PlutusType instance! Above, the inner type
(or representation) of PMaybe was a function. You can use pto to safely take this inner type out-
pto :: Term s a -> Term s (PInner a)
This is quite useful when working with newtypes. Notice how PCurrencySymbol, for example, is simply a newtype to a PByteString. Its
PInner is also PByteString. To be able to use functions that operate on PByteStrings with your PCurrencySymbol, you can simply take
out the PByteString using pto!
Implementing PlutusType for your own types (Data Encoding)
If your type is supposed to be represented using Data encoding instead,
you can derive PlutusType via PlutusTypeData:
data PMyTypeData (a :: S -> Type) (b :: S -> Type) (s :: S)
= POneD (Term s (PAsData a))
| PTwoD (Term s (PAsData b))
deriving stock (Generic)
deriving anyclass (SOP.Generic)
deriving (PlutusType) via (DeriveAsDataStruct (PMyTypeData a b))
Implementing PlutusType for your own types (SoP Encoding)
Mechanism is the same as in Scott encoding case but using DeriveAsSOPStruct instead.
NOTE: You must import
DeriveAsSOPStructwith constructor (like imports at the top of this page do) for GHC to see that the helper is coercible to your own type.
data PMaybeSoP (a :: S -> Type) (s :: S)
= PJustSoP (Term s a)
| PNothingSoP
deriving stock (Generic)
deriving anyclass (SOP.Generic, PEq, PShow)
deriving via DeriveAsSOPStruct (PMaybeSoP a) instance PlutusType (PMaybeSoP a)