{-# OPTIONS --cubical --safe #-}

open import Prelude
open import Algebra

module Data.FingerTree {ā„“} {š‘† : Type ā„“} (mon : Monoid š‘†) where

open Monoid mon

record Measured {a} (A : Type a) : Type (a ā„“āŠ” ā„“) where
  constructor measured
  field μ : A → š‘†

open Measured ⦃ ... ⦄ public

data Digit {a} (A : Type a) : Type a where
  D₁ : A → Digit A
  Dā‚‚ : A → A → Digit A
  Dā‚ƒ : A → A → A → Digit A

data Node {a} (A : Type a) : Type a where
  Nā‚‚ : A → A → Node A
  Nā‚ƒ : A → A → A → Node A

instance
  measuredDigit : ⦃ _ : Measured A ⦄ → Measured (Digit A)
  measuredDigit =
    measured Ī» { (D₁ x) → μ x
               ; (Dā‚‚ x x₁) → μ x āˆ™ μ x₁
               ; (Dā‚ƒ x x₁ xā‚‚) → μ x āˆ™ μ x₁ āˆ™ μ xā‚‚
               }

instance
  measuredNode : ⦃ _ : Measured A ⦄ → Measured (Node A)
  measuredNode =
    measured Ī» { (Nā‚‚ x x₁) → μ x āˆ™ μ x₁
               ; (Nā‚ƒ x x₁ xā‚‚) → μ x āˆ™ μ x₁ āˆ™ μ xā‚‚
               }

record ⟪_⟫ (A : Type a) ⦃ _ : Measured A ⦄ : Type (a ā„“āŠ” ā„“) where
  constructor recd
  field
    val : A
    mem : š‘†
    prf : μ val ≔ mem
open ⟪_⟫ public

memo : ⦃ _ : Measured A ⦄ → A → ⟪ A ⟫
memo x = recd x (μ x) refl

instance
  measuredMemo : ⦃ _ : Measured A ⦄ → Measured ⟪ A ⟫
  measuredMemo = measured mem

mutual
  record Deep {a} (A : Type a) ⦃ _ : Measured A ⦄ : Type (a ā„“āŠ” ā„“) where
    pattern
    constructor more
    inductive
    field
      lbuff : Digit A
      tree  : Tree ⟪ Node A ⟫
      rbuff : Digit A

  data Tree {a} (A : Type a) ⦃ _ : Measured A ⦄ : Type (a ā„“āŠ” ā„“) where
    empty : Tree A
    single : A → Tree A
    deep : ⟪ Deep A ⟫  → Tree A

  μ-deep : āˆ€ {a} {A : Type a} ⦃ _ : Measured A ⦄ → Deep A → š‘†
  μ-deep (more l x r) = μ l āˆ™ (μ-tree x āˆ™ μ r)

  μ-tree : āˆ€ {a} {A : Type a} ⦃ _ : Measured A ⦄ → Tree A → š‘†
  μ-tree empty = ε
  μ-tree (single x) = μ x
  μ-tree (deep xs) = xs .mem

  instance
    Measured-Deep : āˆ€ {a} {A : Type a} → ⦃ _ : Measured A ⦄ → Measured (Deep A)
    Measured-Deep = measured μ-deep

  instance
    Measured-Tree : āˆ€ {a} {A : Type a} → ⦃ _ : Measured A ⦄ → Measured (Tree A)
    Measured-Tree = measured μ-tree
open Deep