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

module Data.List.Kleene where

open import Prelude
open import Data.Fin

mutual
  infixr 5 _&_ ∹_
  infixl 5 _⁺ _⋆
\end{code}
%<*plus-def>
\begin{code}
  record _⁺ (A : Type a) : Type a where
    inductive
    constructor _&_
    field
      head : A
      tail : A 
\end{code}
%</plus-def>
%<*star-def>
\begin{code}
  data _⋆ (A : Type a) : Type a where
    [] : A 
    ∹_ : A   A 
\end{code}
%</star-def>
\begin{code}
open _⁺ public

mutual
  foldr⁺ : (A  B  B)  B  A   B
  foldr⁺ f b (x & xs) = f x (foldr⋆ f b xs)

  foldr⋆ : (A  B  B)  B  A   B
  foldr⋆ f b [] = b
  foldr⋆ f b ( xs) = foldr⁺ f b xs

length⋆ : A   
length⋆ = foldr⋆ (const suc) zero

length⁺ : A   
length⁺ = foldr⁺ (const suc) zero

mutual
  _!⁺_ : (xs : A )  Fin (length⁺ xs)  A
  xs !⁺ f0  = xs .head
  xs !⁺ fs i = xs .tail !⋆ i

  _!⋆_ : (xs : A )  Fin (length⋆ xs)  A
  ( xs) !⋆ i = xs !⁺ i

map⋆ : (A  B)  A   B 
map⋆ f = foldr⋆  x xs   f x & xs) []

map⁺ : (A  B)  A   B 
map⁺ f (x & xs) = f x & map⋆ f xs

mutual
  _⋆++⋆_ : A   A   A 
  [] ⋆++⋆ ys = ys
  ( xs) ⋆++⋆ ys =  (xs ⁺++⋆ ys)

  _⁺++⋆_ : A   A   A 
  head (xs ⁺++⋆ ys) = head xs
  tail (xs ⁺++⋆ ys) = tail xs ⋆++⋆ ys
\end{code}