{-# OPTIONS --cubical-compatible --safe #-}
open import Forcing.Base

module Forcing.Monad (L… : ForcingNotion) where

open import Data.Product
open import Relation.Unary

open ForcingNotion L…

data Ev (P : L  Set) : L  Set where
  now   : {x : L}  P x  Ev P x
  later : {x : L} (R : Cov x)  ({y : L}  y  R  Ev P y)  Ev P x

Monotonic : (L  Set)  Set
Monotonic P = {x y : L}  y  x  P x  P y

module _ {P : L  Set} (k : Monotonic P) where
  weaken-ev : Monotonic (Ev P)
  weaken-ev y≼x (now p)     = now (k y≼x p)
  weaken-ev y≼x (later R f) = later S λ y◁S 
    weaken-ev (proj₁ (proj₂ (g y◁S))) (f (proj₂ (proj₂ (g y◁S))))
    where
    S = proj₁ (stable y≼x R)
    g = proj₂ (stable y≼x R)

module _ {P : L  Set} {F… : Filter L…} where
  open Filter F…

  Ev⇒Filter : {x : L}  Ev P x  F x  Σ[ y  L ] y  x × F y × P y
  Ev⇒Filter (now p)     u = _ , ≼-refl , u , p
  Ev⇒Filter (later R f) u with Ev⇒Filter (f (proj₂ (proj₂ (split u)))) (proj₁ (proj₂ (split u)))
  ... | z , z≼y , Fz , Pz = z , ≼-trans z≼y (◁⇒≼ (proj₂ (proj₂ (split u)))) , Fz , Pz

 : {{x : L}}  (P : {{y : L}}  Set)  Set
 {{x}} P = Ev  y  P {{y}}) x

_⟫=_ : {{x : L}} {P Q : L  Set}  Ev P x  ({{y : L}} {{_ : y  x}}  P y  Ev Q y)  Ev Q x
now   p   ⟫= g = g {{_}} {{≼-refl}} p
later R f ⟫= g = later R  {y} u  _⟫=_ {{y}} (f u) λ {{z}} {{z≼y}}  g {{z}} {{≼-trans z≼y (◁⇒≼ u)}})

fmap : {{x : L}} {P Q : {{y : L}}  Set}  ({{y : L}}  P {{y}}  Q {{y}})   {{x}}  {{y}}  P {{y}})   {{x}}  {{y}}  Q {{y}})
fmap f p = p ⟫= λ {{y}} u  now (f {{y}} u)