```{- proof of nonexistence of join for the composition of two monads
as discussed in http://web.cecs.pdx.edu/~mpj/pubs/RR-1004.pdf

The lemma in Appendix A turns out to be wrong.

map unit : M X → M (N X)
however "MX" is not a suffix of "MNX"!

This is an alternate approach to proving that join does not exist
for the composition of two monads.
-}
module _ where

-- Empty type
data ⊥ : Set where

-- Logical negation
¬_ : Set → Set
¬ x = x → ⊥

infixr 4 _∙_       -- type application
infix 0 _⟶_ _⟶ᵏ_   -- function arrows

-- The domain of types with kind (* → *) that we'll be considering
data *→* : Set where
M N : *→*

-- The domain of types with kind * that we'll be considering
data * : Set where
X   : *
_∙_ : *→* → * → *  -- type application

-- Relation on types defined in the original paper.
-- An inhabitant of (a ⟶ b) indicates that a function
-- having this type can be formed using operations defined
data _⟶_ : * → * → Set where

-- ⟶ is a category
id      : ∀ {a    } → (a ⟶ a)
compose : ∀ {a b c} → (b ⟶ c) → (a ⟶ b) → (a ⟶ c)

map     : ∀ {f a b} → (a ⟶ b) → (f ∙ a ⟶ f ∙ b)
unit    : ∀ {f a  } → (a ⟶ f ∙ a)
join    : ∀ {f a  } → (f ∙ f ∙ a ⟶ f ∙ a)

-- Here we see that the lemma does not hold:
--
-- Lemma:
-- If |- (X -> Y) then (rd X) is a suffix of (rd Y)
--
-- However:
-- MX is not a suffix of MNX
lemma-counter-example : M ∙ X ⟶ M ∙ N ∙ X
lemma-counter-example = map unit

-- Isomorphic relation on types, this representation
-- eliminates the very general 'compose' rule and will
-- be easier to reason about when we prove that there's no
-- join function for the composition of two monads.
--
-- Note how each time we case on a value of this datatype
-- one of the type parameters gets smaller.
data _⟶ᵏ_ : * → * → Set where
pure  : X ⟶ᵏ X
bind  : ∀ {f a b} → (a ⟶ᵏ f ∙ b) → (f ∙ a ⟶ᵏ f ∙ b)
unitᵏ : ∀ {f a b} → (a ⟶ᵏ     b) → (    a ⟶ᵏ f ∙ b)

-- id can be implemented in terms of pure, bind and unitᵏ
idᵏ : ∀ {a} → (a ⟶ᵏ a)
idᵏ {X    } = pure
idᵏ {_ ∙ _} = bind (unitᵏ idᵏ)

-- compose can be implemented in terms of bind and unitᵏ
composeᵏ : ∀ {a b c} → (b ⟶ᵏ c) → (a ⟶ᵏ b) → (a ⟶ᵏ c)
composeᵏ pure             g  = g
composeᵏ (unitᵏ f)        g  = unitᵏ (composeᵏ f g)
composeᵏ (bind  f) (bind  g) = bind (composeᵏ (bind f) g)
composeᵏ (bind  f) (unitᵏ g) = composeᵏ f g

-- Half of the proof of the isomorphism between ⟶ and ⟶ᵏ
to-k : ∀ {a b} → (a ⟶ b) → (a ⟶ᵏ b)
to-k id            = idᵏ
to-k (compose f g) = composeᵏ (to-k f) (to-k g)
to-k (map f)       = bind (unitᵏ (to-k f))
to-k unit          = unitᵏ idᵏ
to-k join          = bind idᵏ

-- Other half of the proof of the isomorphism between ⟶ and ⟶ᵏ
-- We won't actually rely on this, but it shows that these two categories
-- relate exactly the same objects.
from-k : ∀ {a b} → (a ⟶ᵏ b) → (a ⟶ b)
from-k pure      = id
from-k (bind  k) = compose join (map (from-k k))
from-k (unitᵏ k) = compose unit (from-k k)

-- Counter-example to the existence of a generalized join function
-- for the composition of to monads in the ⟶ᵏ category.
impossibleᵏ : ¬ (M ∙ N ∙ M ∙ N ∙ X ⟶ᵏ M ∙ N ∙ X)
impossibleᵏ (bind  (unitᵏ (bind  (unitᵏ ()))))
impossibleᵏ (bind  (unitᵏ (unitᵏ ())))
impossibleᵏ (unitᵏ (unitᵏ ()))

-- Proof of the lack of a generalized join function for the composition of
-- two monads via the counter-example in category ⟶ᵏ
impossible : ¬ (∀ {a} → M ∙ N ∙ M ∙ N ∙ a ⟶ M ∙ N ∙ a)
impossible f = impossibleᵏ (to-k f)
```