Source code on Github
module Common.Denotational where

open import Prelude.Init; open SetAsType
open import Prelude.Monad
open import Prelude.Semigroup
open import Prelude.InferenceRules

-- Types that admit denotational semantics under a certain denotational domain.
record Denote (A : Type ) (Domain : Type ℓ′) : Type ( ⊔ₗ ℓ′) where
  field ⟦_⟧ : A  Domain
open Denote ⦃...⦄ public

-- ** Denotational domains as a state transformers.

Domain₀ : Pred (Type ) _
Domain₀ S = S  S

Domainₑ : Pred (Type ) _
Domainₑ S = S  Maybe S

Denote₀ : Type   Type ℓ′  Type _
Denote₀ A S = Denote A (Domain₀ S)

Denoteₑ : Type   Type ℓ′  Type _
Denoteₑ A S = Denote A (Domainₑ S)

private variable A S : Type 

⟦_⟧₀ :  Denote₀ A S   A  Domain₀ S
⟦_⟧₀ = ⟦_⟧

⟦_⟧ₑ :  Denoteₑ A S   A  Domainₑ S
⟦_⟧ₑ = ⟦_⟧

instance
  -- we denote a ledger as the composition of the denotations of its transactions,
  -- i.e. we run all transactions in sequence
  ⟦List⟧₀ :  Denote₀ A S   Denote₀ (List A) S
  ⟦List⟧₀ .⟦_⟧ = λ where
    []        id
    (x  xs)   xs    x 

  ⟦List⟧ₑ :  Denoteₑ A S   Denoteₑ (List A) S
  ⟦List⟧ₑ .⟦_⟧ = λ where
    []        return
    (x  xs)   x  >=>  xs 

comp₀ :   _ : Denote₀ A S  {l l′ : List A} 
   (s : S)   l  l′ ⟧₀ s  ( l′ ⟧₀   l ⟧₀) s
comp₀ {l = []}    = λ _  refl
comp₀ {l = x  l} = comp₀ {l = l}   x ⟧₀

comp :  {S : Type }  _ : Denoteₑ A S  {l l′ : List A} 
   (s : S)   l ++ l′ ⟧ₑ s  ( l ⟧ₑ >=>  l′ ⟧ₑ) s
comp {l = []}    _ = refl
comp {l = x  l} s with  x  s
... | nothing = refl
... | just s′ = comp {l = l} s′