\begin{code}
{-# OPTIONS --safe #-}

open import Prelude
open import Algebra
open import Algebra.Monus

module Codata.Pairing {S : Type} (mon : TMAPOM S) where

open TMAPOM mon
open import Codata.Chain S

infixr 5 _◂_
record Heap (A : Type) : Type where
  coinductive; constructor _◂_
  field  extract  : A
         unwrap   : List (S × Heap A)
open Heap public

out : Heap A  A × List (S × Heap A)
out xs = extract xs , unwrap xs

module _ {A : Type} (ψ : B  A × List (S × B)) where
  hana  : B  Heap A
  hana′ : A × List (S × B)  Heap A
  hana″ : List (S × B)  List (S × Heap A)

  hana = hana′  ψ

  hana′ (x , xs) .extract = x
  hana′ (x , xs) .unwrap = hana″ xs

  hana″ [] = []
  hana″ ((w , x)  xs) = (w , hana x)  hana″ xs


open import Data.Link S

open import Data.NonEmpty

_⋈_ : S × Heap A  S × Heap A  S × Heap A
(wₗ , lls)  (wᵣ , rrs) with wₗ ≤|≥ wᵣ
... | inl  (wᵣ∸wₗ  , _)  = wₗ  , extract lls   (wᵣ∸wₗ  , rrs)   unwrap lls
... | inr  (wₗ∸wᵣ  , _)  = wᵣ  , extract rrs   (wₗ∸wᵣ  , lls)   unwrap rrs

\end{code}
%<*merges-pl>
\begin{code}
merges⁺ :  S × Heap A  List (S × Heap A) 
          S × Heap A
merges⁺ x₁  [] = x₁
merges⁺ x₁  (x₂  []) = x₁  x₂
merges⁺ x₁  (x₂  x₃  xs) =
  (x₁  x₂)  merges⁺ x₃ xs
\end{code}
%</merges-pl>
%<*merges>
\begin{code}
merges :  List (S × Heap A)
         Link (Heap A)
merges [] = ⟨⟩
merges (x  xs) = just (merges⁺ x xs)
\end{code}
%</merges>
\begin{code}

open Functor ⦃...⦄
\end{code}
%<*search>
\begin{code}
search : Heap A  Chain A
search = ana (map₂ merges  out)
\end{code}
%</search>
\begin{code}
private module HeapGraph where
  GraphOf : Type  Type
  GraphOf A = A  List (S × A)

  trace-heap : GraphOf A  A  Heap A
  trace-heap f = hana  x  x , f x)
  
  pathed : GraphOf A  GraphOf (List⁺ A)
  pathed g (v  vs) = mapl (map₂ (_∷ v  vs)) (g v)

  filterg : (A  Bool)  GraphOf A  GraphOf A
  filterg p g x = if p x then g x else []

  module _ {V} (disc : Discrete V) where
    open import Data.NonEmpty.Discrete disc

    dijkstra : V  GraphOf V  Chain (List⁺ V)
    dijkstra s g = search (trace-heap (filterg uniq (pathed g)) (s  []))

\end{code}