imports

{-# LANGUAGE UndecidableInstances #-}

module Plutarch.Docs.PEqAndPOrd (PMaybe'(..)) where

import Data.Kind (Type)
import GHC.Generics (Generic)
import Generics.SOP qualified as SOP
import Plutarch.Prelude

PEq & POrd

Plutarch level equality is provided by the PEq typeclass:

class PEq t where
  (#==) :: Term s t -> Term s t -> Term s PBool

PInteger implements PEq as you would expect. So you could do:

1 #== 2

That would yield a Term s PBool, which you would probably use with pif (or similar).

Similarly, POrd emulates Ord:

-- The actual POrd has more methods, but these are the only required ones.
class PEq => POrd t where
  (#<) :: Term s t -> Term s t -> Term s PBool
  (#<=) :: Term s t -> Term s t -> Term s PBool

It works as you would expect:

pif (1 #< 7) "indeed" "what"

evaluates to "indeed" - of type Term s PString.

For SOP encoded types, you can easily derive PEq via generic deriving:

data PMaybe' a s
  = PNothing'
  | PJust' (Term s a)
  deriving stock (Generic)
  deriving anyclass (SOP.Generic, PEq)
  deriving (PlutusType) via (DeriveAsSOPStruct (PMaybe' a))

For data encoded types, you can derive PEq via their data representation:

data PTriplet (a :: S -> Type) (s :: S)
  = PTriplet
      { ptriplet'a :: Term s (PAsData a)
      , ptriplet'b :: Term s (PAsData a)
      , ptriplet'c :: Term s (PAsData a)
      }
  deriving stock (Generic)
  deriving anyclass (SOP.Generic, PIsData, PEq)
  deriving (PlutusType) via (DeriveAsDataStruct (PTriplet a))

Aside: PEq derivation for data encoded types uses "Data equality". It simply ensures the structure (as represented through data encoding) of both values are exactly the same. It does not take into account any custom PEq instances for the individual fields within.