Skip to content

Commit 5c27f90

Browse files
authored
[ fix #693 ] Change the definition of FreeMonad (#1819)
1 parent 3590a48 commit 5c27f90

File tree

3 files changed

+161
-32
lines changed

3 files changed

+161
-32
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ Bug-fixes
4949
re-exported in their full generality which would lead to unsolved meta variables at
5050
their use sites.
5151

52+
* In `Data.Container.FreeMonad`, we give a direct definition of `_⋆_` as an inductive
53+
type rather than encoding it as an instance of `μ`. This ensures Agda notices that
54+
`C ⋆ X` is strictly positive in `X` which in turn allows us to use the free monad
55+
when defining auxiliary (co)inductive types (cf. the `Tap` example in
56+
`README.Data.Container.FreeMonad`).
57+
5258
* In `Data.Maybe.Base` the fixity declaration of `_<∣>_` was missing. This has been fixed.
5359

5460
Non-backwards compatible changes

README/Data/Container/FreeMonad.agda

+65-13
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,23 @@
99

1010
module README.Data.Container.FreeMonad where
1111

12+
open import Level using (0ℓ)
1213
open import Effect.Monad
1314
open import Data.Empty
1415
open import Data.Unit
1516
open import Data.Bool.Base using (Bool; true)
1617
open import Data.Nat
1718
open import Data.Sum using (inj₁; inj₂)
1819
open import Data.Product renaming (_×_ to _⟨×⟩_)
19-
open import Data.Container
20+
open import Data.Container using (Container; _▷_)
2021
open import Data.Container.Combinator
21-
open import Data.Container.FreeMonad
22+
open import Data.Container.FreeMonad as FreeMonad
2223
open import Data.W
2324
open import Relation.Binary.PropositionalEquality as P
2425

2526
------------------------------------------------------------------------
27+
-- Defining the signature of an effect and building trees describing
28+
-- computations leveraging that effect.
2629

2730
-- The signature of state and its (generic) operations.
2831

@@ -33,29 +36,25 @@ State S = ⊤ ⟶ S ⊎ S ⟶ ⊤
3336
I ⟶ O = I ▷ λ _ O
3437

3538
get : {S} State S ⋆ S
36-
get = inn (inj₁ _ , return)
37-
where
38-
open RawMonad rawMonad
39+
get = impure (inj₁ _ , pure)
3940

4041
put : {S} S State S ⋆ ⊤
41-
put s = inn (inj₂ s , return)
42-
where
43-
open RawMonad rawMonad
42+
put s = impure (inj₂ s , pure)
4443

4544
-- Using the above we can, for example, write a stateful program that
4645
-- delivers a boolean.
4746
prog : State ℕ ⋆ Bool
4847
prog =
4948
get >>= λ n
5049
put (suc n) >>
51-
return true
50+
pure true
5251
where
53-
open RawMonad rawMonad
52+
open RawMonad rawMonad using (_>>_)
5453

5554
runState : {S X : Set} State S ⋆ X (S X ⟨×⟩ S)
56-
runState (sup (inj₁ x , _)) = λ s x , s
57-
runState (sup (inj₂ (inj₁ _) , k)) = λ s runState (k s) s
58-
runState (sup (inj₂ (inj₂ s) , k)) = λ _ runState (k _) s
55+
runState (pure x) = λ s x , s
56+
runState (impure ((inj₁ _) , k)) = λ s runState (k s) s
57+
runState (impure ((inj₂ s) , k)) = λ _ runState (k _) s
5958

6059
test : runState prog 0 ≡ (true , 1)
6160
test = P.refl
@@ -64,3 +63,56 @@ test = P.refl
6463
-- could quotient @State S ⋆ X@ by the seven axioms of state (see
6564
-- Plotkin and Power's "Notions of Computation Determine Monads", 2002)
6665
-- then we would get the state monad.
66+
67+
------------------------------------------------------------------------
68+
-- Defining effectful inductive data structures
69+
70+
-- The definition of `C ⋆ A` is strictly positive in `A`, meaning that we
71+
-- can use `C ⋆_` when defining (co)inductive datatypes.
72+
73+
74+
open import Size
75+
open import Codata.Sized.Thunk
76+
open import Data.Vec.Base using (Vec; []; _∷_)
77+
78+
79+
-- A `Tap C A` is a infinite source of `A`s provided that we can perform
80+
-- the effectful computations described by `C`.
81+
-- The first one can be accessed readily but the rest of them is hidden
82+
-- under layers of `C` computations.
83+
84+
module _ (C : Container 0ℓ 0ℓ) (A : Set 0ℓ) where
85+
86+
data Tap (i : Size) : Set 0ℓ where
87+
_∷_ : A Thunk (λ i C ⋆ Tap i) i Tap i
88+
89+
-- We can run a given tap for a set number of steps and collect the elements
90+
-- thus generated along the way. This gives us a `C ⋆_` computation of a vector.
91+
92+
module _ {C : Container 0ℓ 0ℓ} {A : Set 0ℓ} where
93+
94+
take : Tap C A _ (n : ℕ) C ⋆ Vec A n
95+
take _ 0 = pure []
96+
take (x ∷ _) 1 = pure (x ∷ [])
97+
take (x ∷ mxs) (suc n) = do
98+
xs mxs .force
99+
rest take xs n
100+
pure (x ∷ rest)
101+
102+
-- A stream of all the natural numbers starting from a given value is an
103+
-- example of a tap.
104+
105+
natsFrom : {i} State ℕ ⋆ Tap (State ℕ) ℕ i
106+
natsFrom = let open RawMonad rawMonad using (_>>_) in do
107+
n get
108+
put (suc n)
109+
pure (n ∷ λ where .force natsFrom)
110+
111+
-- We can use `take` to capture an initial segment of the `natsFrom` tap
112+
-- and, after running the state operations, observe that it does generate
113+
-- successive numbers.
114+
115+
_ : k
116+
runState (natsFrom >>= λ ns take ns 5) k
117+
≡ (k ∷ 1 + k ∷ 2 + k ∷ 3 + k ∷ 4 + k ∷ [] , 5 + k)
118+
_ = λ k refl

src/Data/Container/FreeMonad.agda

+90-19
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,23 @@
88

99
module Data.Container.FreeMonad where
1010

11-
open import Level
11+
open import Level using (Level; _⊔_)
1212
open import Data.Sum.Base using (inj₁; inj₂ ; [_,_]′)
13-
open import Data.Product
14-
open import Data.Container
13+
open import Data.Product using (_,_; -,_)
14+
open import Data.Container using (Container; ⟦_⟧; μ)
15+
open import Data.Container.Relation.Unary.All using (□; all)
1516
open import Data.Container.Combinator using (const; _⊎_)
16-
open import Data.W using (sup)
17-
open import Effect.Monad
17+
open import Data.W as W using (sup)
18+
open import Effect.Functor using (RawFunctor)
19+
open import Effect.Applicative using (RawApplicative)
20+
open import Effect.Monad using (RawMonad)
21+
open import Function.Base as Function using (_$_; _∘_)
22+
23+
variable
24+
x y s p ℓ : Level
25+
C : Container s p
26+
X : Set x
27+
Y : Set y
1828

1929
infixl 1 _⋆C_
2030
infix 1 _⋆_
@@ -29,28 +39,89 @@ infix 1 _⋆_
2939
-- A useful intuition is to think of containers describing single
3040
-- operations and the free monad construction over a container and a set
3141
-- describing a tree of operations as nodes and elements of the set as
32-
-- leafs. If one starts at the root, then any path will pass finitely
42+
-- leaves. If one starts at the root, then any path will pass finitely
3343
-- many nodes (operations described by the container) and eventually end
3444
-- up in a leaf (element of the set) -- hence the Kleene star notation
3545
-- (the type can be read as a regular expression).
3646

47+
------------------------------------------------------------------------
48+
-- Type definition
49+
50+
-- The free moand can be defined as the least fixpoint `μ (C ⋆C X)`
51+
3752
_⋆C_ : {x s p} Container s p Set x Container (s ⊔ x) p
3853
C ⋆C X = const X ⊎ C
3954

40-
_⋆_ : {x s p} Container s p Set x Set (x ⊔ s ⊔ p)
41-
C ⋆ X = μ (C ⋆C X)
55+
-- However Agda's positivity checker is currently too weak to observe
56+
-- that `X` is used in a strictly positive manner in `μ (C ⋆C X)` as
57+
-- demonstrated in #693.
58+
-- So we provide instead an inductive definition that we prove to be
59+
-- equivalent to the μ-based one.
60+
61+
data _⋆_ (C : Container s p) (X : Set x) : Set (x ⊔ s ⊔ p) where
62+
pure : X C ⋆ X
63+
impure : ⟦ C ⟧ (C ⋆ X) C ⋆ X
64+
65+
------------------------------------------------------------------------
66+
-- Equivalent types
67+
68+
-- We can prove that `C ⋆ X` is equivalent to one layer of `C ⋆C X` with
69+
-- subterms of tyep `C ⋆ X`.
70+
71+
inj : {X : Set x} ⟦ C ⋆C X ⟧ (C ⋆ X) C ⋆ X
72+
inj (inj₁ x , _) = pure x
73+
inj (inj₂ c , r) = impure (c , r)
74+
75+
out : {X : Set x} C ⋆ X ⟦ C ⋆C X ⟧ (C ⋆ X)
76+
out (pure x) = inj₁ x , λ ()
77+
out (impure (c , r)) = inj₂ c , r
78+
79+
-- We can fully convert back and forth between `C ⋆ X` and `μ (C ⋆C X)`.
4280

43-
module _ {s p} {C : Container s p} where
81+
toμ : C ⋆ X μ (C ⋆C X)
82+
toμ (pure x) = sup (inj₁ x , λ ())
83+
toμ (impure (c , r)) = sup (inj₂ c , toμ ∘ r)
84+
85+
fromμ : μ (C ⋆C X) C ⋆ X
86+
fromμ = W.foldr inj
87+
88+
-- We can recover an induction principle similar to the one given in `Data.W`.
89+
-- We curry these ones by distinguishing the pure vs. impure case
90+
91+
module _ (P : C ⋆ X Set ℓ)
92+
(algP : x P (pure x))
93+
(algI : {t} □ C P t P (impure t)) where
94+
95+
induction : (t : C ⋆ X) P t
96+
induction (pure x) = algP x
97+
induction (impure (c , r)) = algI $ all (induction ∘ r)
98+
99+
module _ {P : Set ℓ}
100+
(algP : X P)
101+
(algI : ⟦ C ⟧ P P) where
102+
103+
foldr : C ⋆ X P
104+
foldr = induction (Function.const P) algP (algI ∘ -,_ ∘ □.proof)
105+
106+
_<$>_ : (X Y) C ⋆ X C ⋆ Y
107+
f <$> t = foldr (pure ∘ f) impure t
108+
109+
_<*>_ : C ⋆ (X Y) C ⋆ X C ⋆ Y
110+
pure f <*> t = f <$> t
111+
impure (c , r) <*> t = impure (c , λ v r v <*> t)
112+
113+
_>>=_ : C ⋆ X (X C ⋆ Y) C ⋆ Y
114+
pure x >>= f = f x
115+
impure (c , r) >>= f = impure (c , λ v r v >>= f)
116+
117+
------------------------------------------------------------------------
118+
-- Structure
44119

45-
inn : {x} {X : Set x} ⟦ C ⟧ (C ⋆ X) C ⋆ X
46-
inn (s , f) = sup (inj₂ s , f)
120+
rawFunctor : RawFunctor (_⋆_ {x = x} C)
121+
rawFunctor = record { _<$>_ = _<$>_ }
47122

48-
rawMonad : {x} RawMonad {s ⊔ p ⊔ x} (C ⋆_)
49-
rawMonad = record { return = return; _>>=_ = _>>=_ }
50-
where
51-
return : {X} X C ⋆ X
52-
return x = sup (inj₁ x , λ ())
123+
rawApplicative : {C : Container s p} RawApplicative (_⋆_ {x = x ⊔ s ⊔ p} C)
124+
rawApplicative = record { pure = pure ; _⊛_ = _<*>_ }
53125

54-
_>>=_ : {X Y} C ⋆ X (X C ⋆ Y) C ⋆ Y
55-
sup (inj₁ x , _) >>= k = k x
56-
sup (inj₂ s , f) >>= k = inn (s , λ p f p >>= k)
126+
rawMonad : {C : Container s p} RawMonad (_⋆_ {x = x ⊔ s ⊔ p} C)
127+
rawMonad = record { return = pure ; _>>=_ = _>>=_ }

0 commit comments

Comments
 (0)