module IndexedStreamProg where
open import Coinduction
import Stream as S
open S using (Stream; _≺_)
open import Data.Nat
import Data.Vec as V
open V using (Vec; []; _∷_)
import IO
data Ord : Set where
lt : Ord
eq : Ord
gt : Ord
infixr 5 _≺_ _≺≺_
data Prog (A : Set) : ℕ → ℕ → Set1 where
_≺≺_ : ∀ {m} (xs′ : Vec A m) (xs″ : ∞₁ (Prog A m m)) → Prog A m m
forget : ∀ {m n} (xs : Prog A m (suc n)) → Prog A m n
_≺_ : ∀ {m n} (x : A) (xs : Prog A m n) → Prog A m (suc n)
tail : ∀ {m n} (xs : Prog A m (suc n)) → Prog A m n
zipWith : ∀ {m n B C} (f : B → C → A)
(xs : Prog B m n) (ys : Prog C m n) → Prog A m n
map : ∀ {m n B} (f : B → A) (xs : Prog B m n) → Prog A m n
merge : (cmp : A → A → Ord)
(xs : Prog A 1 1) (ys : Prog A 1 1) → Prog A 1 1
data WHNF A m n : Set1 where
_≺≺_ : (xs′ : Vec A n) (xs″ : Prog A m m) → WHNF A m n
whnf : ∀ {A m n} → Prog A m n → WHNF A m n
whnf (xs′ ≺≺ xs″) = xs′ ≺≺ ♭₁ xs″
whnf (forget xs) with whnf xs
whnf (forget xs) | xs′ ≺≺ xs″ = V.init xs′ ≺≺ forget (V.last xs′ ≺ xs″)
whnf (x ≺ xs) with whnf xs
whnf (x ≺ xs) | xs′ ≺≺ xs″ = (x ∷ xs′) ≺≺ xs″
whnf (tail xs) with whnf xs
whnf (tail xs) | xs′ ≺≺ xs″ = V.tail xs′ ≺≺ xs″
whnf (zipWith f xs ys) with whnf xs | whnf ys
whnf (zipWith f xs ys) | xs′ ≺≺ xs″ | ys′ ≺≺ ys″ =
V.zipWith f xs′ ys′ ≺≺ zipWith f xs″ ys″
whnf (map f xs) with whnf xs
whnf (map f xs) | xs′ ≺≺ xs″ = V.map f xs′ ≺≺ map f xs″
whnf (merge cmp xs ys) with whnf xs | whnf ys
whnf (merge cmp xs ys) | (x ∷ []) ≺≺ xs″ | (y ∷ []) ≺≺ ys″ with cmp x y
... | lt = (x ∷ []) ≺≺ merge cmp xs″ (forget (y ≺ ys″))
... | eq = (x ∷ []) ≺≺ merge cmp xs″ ys″
... | gt = (y ∷ []) ≺≺ merge cmp (forget (x ≺ xs″)) ys″
mutual
value : ∀ {A m n} → WHNF A (suc m) (suc n) → Stream A
value ((x ∷ []) ≺≺ ys) = x ≺ ♯ ⟦ ys ⟧
value ((x ∷ (x' ∷ xs)) ≺≺ ys) = x ≺ ♯ value ((x' ∷ xs) ≺≺ ys)
⟦_⟧ : ∀ {A m n} → Prog A (suc m) (suc n) → Stream A
⟦ xs ⟧ = value (whnf xs)
fib : Prog ℕ 1 1
fib = (0 ∷ []) ≺≺ ♯₁ (1 ≺ zipWith _+_ (forget fib) (tail fib))
hamming : Prog ℕ 1 1
hamming = (1 ∷ []) ≺≺ ♯₁ merge cmp (map (_*_ 2) hamming)
(map (_*_ 3) hamming)
where
toOrd : ∀ {m n} → Ordering m n → Ord
toOrd (less _ _) = lt
toOrd (equal _) = eq
toOrd (greater _ _) = gt
cmp : ℕ → ℕ → Ord
cmp m n = toOrd (compare m n)
main = IO.run (S.putStream (S._⋎_ ⟦ fib ⟧ ⟦ hamming ⟧))