module Chapter6.IDesc.FreeMonad.Examples.FileSystem where

open import Level hiding (zero ; suc)

open import Data.Unit
open import Data.Nat hiding (_*_)
open import Data.Fin hiding (lift)
open import Data.Vec hiding (_>>=_)
open import Data.Product
open import Data.String

open import Relation.Binary.PropositionalEquality

open import Chapter2.Logic

open import Chapter5.IDesc
open import Chapter5.IDesc.Tagged
open import Chapter5.IDesc.Fixpoint

open import Chapter6.IDesc.FreeMonad
open import Chapter6.IDesc.FreeMonad.IMonad
open import Chapter6.IDesc.FreeMonad.Monad


data State : Set where
  Closed Open : State

infix 50 _⊢_
_⊢_ : {I : Set}(X : Set)(k : I)  Pow I
X  k = λ k'  k'  k × X

-- Or, equivalently:
--data _⊢_ {I : Set}(X : Set)(k : I) : Pow I where
--  witness : (wit : X) → (X ⊢ k) k


ΣFS : tagDesc _ State
ΣFS = (0 ,  _  [])) ,
       { Closed  1 
         ; Open  2 }) ,
       { Closed  -- open:
                    ( String λ _  
                    ( State λ s 
                       λ _  
                     `var s)  `1)   [] 
         ; Open  -- read:
                  ( State λ s  
                    (s  Open × String) λ _ 
                   `var s)  `1 
                  -- close:
                  ( State λ s 
                    (s  Closed × ) λ _  
                   `var s)  `1  [] })

FS : (State  Set)  State  Set
FS = _*_ ΣFS

return : ∀{X}  X  FS X
return = `v {D = ΣFS}


openFile : (fname : String)  FS  _  ) Closed
openFile fname =  lift (suc zero) , fname ,  s  return {X = λ _  }) , lift tt 

readFile : FS  s  s  Open × String) Open
readFile =  lift (suc zero)  ,  s  return {X = String  Open})  , lift tt 

closeFile : FS  s  s  Closed × ) Open
closeFile =  lift (suc (suc zero)) ,  s  return {X =   Closed}) , lift tt 


example : FS  s  s  Closed × String) Closed
example = openFile "test.txt" >>= λ {
          {Closed} tt  
            -- File do not exists, silently abort
            return (refl , "") ; 
          {Open} tt  
            -- File successfully opened
            readFile >>= λ {
            -- Upon reading, file stays open:
            {Closed} (() , _) ; 
            {Open} (refl , str)  
              closeFile >>= λ {
              -- Upon closing, file is closed:
              {Open} (() , _) ; 
              {Closed} (refl , tt)  
                return (refl , str) }}}
  where open RawIMonad (monad ΣFS) hiding (return)