Utils

module Utils where

Imports

open import Relation.Binary.PropositionalEquality using (_≡_;refl;cong;sym;trans;cong₂;subst)
open import Function using (const;_∘_)
open import Data.Nat using (;zero;suc;_≤‴_;_≤_;_+_)
open _≤_
open _≤‴_
open import Data.Nat.Properties
               using (+-suc;m+1+n≢m;+-cancelˡ-≡;m≢1+n+m;m+1+n≢0;+-cancelʳ-≡;+-assoc;+-comm;+-identityʳ)
open import Relation.Binary using (Decidable)
import Data.Integer as I
import Data.List as L
open import Data.Sum using (_⊎_;inj₁;inj₂)
open import Relation.Nullary using (Dec;yes;no;¬_)
open import Data.Empty using (;⊥-elim)
open import Data.Integer using ()
open import Data.String using (String)
open import Data.Bool using (Bool)
open import Data.Maybe using (Maybe; just; nothing; maybe)
                           renaming (_>>=_ to mbind) public
open import Data.Unit using ()

{-# FOREIGN GHC import Raw #-}

Either

We cannot use the standard library’s Either as it is not set up to compile the Haskell’s Either and compile pragmas have to go in the same module as definitions.

data Either (A B : Set) : Set where
  inj₁ : A  Either A B
  inj₂ : B  Either A B

{-# COMPILE GHC Either = data Either (Left | Right) #-}

either : {A B C : Set}  Either A B  (A  C)  (B  C)  C
either (inj₁ a) f g = f a
either (inj₂ b) f g = g b

eitherBind : ∀{A B E}  Either E A  (A  Either E B)  Either E B
eitherBind (inj₁ e) f = inj₁ e
eitherBind (inj₂ a) f = f a

decIf : ∀{A B : Set}  Dec A  B  B  B
decIf (yes p) t f = t
decIf (no ¬p) t f = f

cong₃ : {A B C D : Set}  (f : A  B  C  D)
   {a a' : A}  a  a'
   {b b' : B}  b  b'
   {c c' : C}  c  c'
   f a b c  f a' b' c'
cong₃ f refl refl refl = refl

≡-subst-removable :  {a p} {A : Set a}
                    (P : A  Set p) {x y} (p q : x  y) z 
                    subst P p z  subst P q z
≡-subst-removable P refl refl z = refl

Natural Sum Type

The type n ∔ n' ≡ m takes two naturals n and n' such that they sum to m. It is helpful when one wants to do m things, while keeping track of the number of done things (n) and things to do (n').

data _∔_≣_ :       Set where
  start : (n : )   0  n  n
  bubble : ∀{n n' m : }  n  suc n'  m  suc n  n'  m

unique∔ : ∀{n n' m : }(p p' : n  n'  m)  p  p'
unique∔ (start _) (start _) = refl
unique∔ (bubble p) (bubble p') = cong bubble (unique∔ p p')


+2∔ : ∀(n m t : )  n + m  t  n  m  t
+2∔ zero m .(zero + m) refl = start _
+2∔ (suc n) m t p = bubble (+2∔ n (suc m) t (trans (+-suc n m) p))

∔2+ : ∀{n m t : }  n  m  t   n + m  t
∔2+ (start _) = refl
∔2+ (bubble bt) = trans (sym (+-suc _ _)) (∔2+ bt)

alldone : ∀(n : )  n  zero  n
alldone n = +2∔ n 0 n (+-identityʳ n)

Monads

This introduces the Monad operators.

record Monad (F : Set  Set) : Set₁ where
  field
    return : ∀{A}  A  F A
    _>>=_   : ∀{A B}  F A  (A  F B)  F B

  _>>_ : ∀{A B}  F A  F B  F B
  as >> bs = as >>= const bs

  fmap : ∀{A B}  (A  B)  F A  F B
  fmap f as = as >>= (return  f)

open Monad  public

instance
  MaybeMonad : Monad Maybe
  MaybeMonad = record { return = just ; _>>=_ = mbind }

sumBind : {A B C : Set}  A  C  (A  B  C)  B  C
sumBind (inj₁ a) f = f a
sumBind (inj₂ c) f = inj₂ c

SumMonad : (C : Set)  Monad (_⊎ C)
SumMonad A = record { return = inj₁ ; _>>=_ = sumBind }

EitherMonad : (E : Set)  Monad (Either E)
EitherMonad E = record { return = inj₂ ; _>>=_ = eitherBind }

-- one instance to rule them all...
instance
  EitherP : {A : Set}  Monad (Either A)
  Monad.return EitherP = inj₂
  Monad._>>=_ EitherP  = eitherBind

withE : {A B C : Set}  (A  B)  Either A C  Either B C
withE f (inj₁ a) = inj₁ (f a)
withE f (inj₂ c) = inj₂ c

dec2Either : {A : Set}  Dec A  Either (¬ A) A
dec2Either (yes p) = inj₂ p
dec2Either (no ¬p) = inj₁ ¬p

Writer Monad

record Writer (M : Set)(A : Set) : Set where
   constructor _,_
   field
     wrvalue : A
     accum : M

module WriterMonad {M : Set}(e : M)(_∙_ : M  M  M) where
  instance
    WriterMonad : Monad (Writer M)
    Monad.return WriterMonad x = x , e
    (WriterMonad Monad.>>= (x , w)) f = let (y , w') = f x in y , (w  w')

  tell : (w : M)  Writer M 
  tell w = _ , w

Errors and ByteStrings

data RuntimeError : Set where
  gasError : RuntimeError
  userError : RuntimeError
  runtimeTypeError : RuntimeError

{-# COMPILE GHC RuntimeError = data RuntimeError (GasError | UserError | RuntimeTypeError) #-}

postulate ByteString : Set
{-# FOREIGN GHC import qualified Data.ByteString as BS #-}
{-# COMPILE GHC ByteString = type BS.ByteString #-}

postulate
  eqByteString : ByteString  ByteString  Bool
{-# COMPILE GHC eqByteString = (==) #-}

Record Types

record _×_ (A B : Set) : Set where
    constructor _,_
    field
      proj₁ : A
      proj₂ : B

infixr 4 _,_
infixr 2 _×_

{-# FOREIGN GHC type Pair a b = (a , b) #-}
{-# COMPILE GHC _×_ = data Pair ((,))  #-}

Lists and Maps

data List (A : Set) : Set where
  []  : List A
  _∷_ : A  List A  List A

length :  {A}  List A  
length [] = 0
length (x  xs) = suc (length xs)

map : ∀{A B}  (A  B)  List A  List B
map f [] = []
map f (x  xs) = f x  map f xs

toList : ∀{A}   List A  L.List A
toList [] = L.[]
toList (x  xs) = x L.∷ toList xs

fromList : ∀{A}   L.List A  List A
fromList L.[] = []
fromList (x L.∷ xs) = x  fromList xs

map-cong : ∀{A B : Set}{xs : L.List A}{f g : A  B}
      (∀ x  f x  g x)
      L.map f xs  L.map g xs
map-cong {xs = L.[]} p = refl
map-cong {xs = x L.∷ xs} p = cong₂ L._∷_ (p x) (map-cong p)

infixr 5 _∷_

{-# COMPILE GHC List = data [] ([] | (:)) #-}

DATA

data DATA : Set where
  ConstrDATA :  I.ℤ  List DATA  DATA
  MapDATA : List (DATA × DATA)  DATA
  ListDATA : List DATA  DATA
  iDATA : I.ℤ  DATA
  bDATA : ByteString  DATA

{-# FOREIGN GHC import PlutusCore.Data as D #-}
{-# COMPILE GHC DATA = data Data (D.Constr | D.Map | D.List | D.I | D.B)   #-}

postulate eqDATA : DATA  DATA  Bool
{-# COMPILE GHC eqDATA = (==) #-}

postulate Bls12-381-G1-Element : Set
{-# FOREIGN GHC import qualified PlutusCore.Crypto.BLS12_381.G1 as G1 #-}
{-# COMPILE GHC Bls12-381-G1-Element = type G1.Element #-}

postulate
  eqBls12-381-G1-Element : Bls12-381-G1-Element  Bls12-381-G1-Element  Bool
{-# COMPILE GHC eqBls12-381-G1-Element = (==) #-}

postulate Bls12-381-G2-Element : Set
{-# FOREIGN GHC import qualified PlutusCore.Crypto.BLS12_381.G2 as G2 #-}
{-# COMPILE GHC Bls12-381-G2-Element = type G2.Element #-}

postulate
  eqBls12-381-G2-Element : Bls12-381-G2-Element  Bls12-381-G2-Element  Bool
{-# COMPILE GHC eqBls12-381-G2-Element = (==) #-}

postulate Bls12-381-MlResult : Set
{-# FOREIGN GHC import qualified PlutusCore.Crypto.BLS12_381.Pairing as Pairing #-}
{-# COMPILE GHC Bls12-381-MlResult = type Pairing.MlResult #-}

postulate
  eqBls12-381-MlResult : Bls12-381-MlResult  Bls12-381-MlResult  Bool
{-# COMPILE GHC eqBls12-381-MlResult = (==) #-}

Kinds

The kind of types is *. Plutus core core is based on System Fω which is higher order so we have for type level functions. We also have a kind called # which is used for builtin types.

data Kind : Set where
  *   : Kind               -- type
     : Kind               -- builtin
  _⇒_ : Kind  Kind  Kind -- function kind

{-# COMPILE GHC Kind = data KIND (Star | Sharp | Arrow )         #-}

Let I, J, K range over kinds:

variable
  I J K : Kind