Skip to content

Codata.Musical.Stream

------------------------------------------------------------------------
-- The Agda standard library
--
-- Streams
------------------------------------------------------------------------

{-# OPTIONS --cubical-compatible --guardedness #-}

module Codata.Musical.Stream where

open import Level using (Level)
open import Codata.Musical.Notation
open import Codata.Musical.Colist using (Colist; []; _∷_)
open import Data.Vec.Base using (Vec; []; _∷_)
open import Data.Nat.Base using (β„•; zero; suc)
open import Relation.Binary.Definitions
  using (Reflexive; Symmetric; Transitive)
open import Relation.Binary.Bundles using (Setoid)
open import Relation.Binary.PropositionalEquality.Core as ≑ using (_≑_)

private
  variable
    a b c : Level
    A : Set a
    B : Set b
    C : Set c

------------------------------------------------------------------------
-- The type

infixr 5 _∷_

data Stream (A : Set a) : Set a where
  _∷_ : (x : A) (xs : ∞ (Stream A)) β†’ Stream A

{-# FOREIGN GHC
  data AgdaStream a = Cons a (MAlonzo.RTE.Inf (AgdaStream a))
  type AgdaStream' l a = AgdaStream a
  #-}
{-# COMPILE GHC Stream = data AgdaStream' (Cons) #-}

------------------------------------------------------------------------
-- Some operations

head : Stream A β†’ A
head (x ∷ xs) = x

tail : Stream A β†’ Stream A
tail (x ∷ xs) = β™­ xs

map : (A β†’ B) β†’ Stream A β†’ Stream B
map f (x ∷ xs) = f x ∷ β™― map f (β™­ xs)

zipWith : (A β†’ B β†’ C) β†’ Stream A β†’ Stream B β†’ Stream C
zipWith _βˆ™_ (x ∷ xs) (y ∷ ys) = (x βˆ™ y) ∷ β™― zipWith _βˆ™_ (β™­ xs) (β™­ ys)

take : βˆ€ n β†’ Stream A β†’ Vec A n
take zero    xs       = []
take (suc n) (x ∷ xs) = x ∷ take n (β™­ xs)

drop : β„• β†’ Stream A β†’ Stream A
drop zero    xs       = xs
drop (suc n) (x ∷ xs) = drop n (β™­ xs)

repeat : A β†’ Stream A
repeat x = x ∷ β™― repeat x

iterate : (A β†’ A) β†’ A β†’ Stream A
iterate f x = x ∷ β™― iterate f (f x)

-- Interleaves the two streams.

infixr 5 _β‹Ž_

_β‹Ž_ : Stream A β†’ Stream A β†’ Stream A
(x ∷ xs) β‹Ž ys = x ∷ β™― (ys β‹Ž β™­ xs)

mutual

  -- Takes every other element from the stream, starting with the
  -- first one.

  evens : Stream A β†’ Stream A
  evens (x ∷ xs) = x ∷ β™― odds (β™­ xs)

  -- Takes every other element from the stream, starting with the
  -- second one.

  odds : Stream A β†’ Stream A
  odds (x ∷ xs) = evens (β™­ xs)

toColist : Stream A β†’ Colist A
toColist (x ∷ xs) = x ∷ β™― toColist (β™­ xs)

lookup : Stream A β†’ β„• β†’ A
lookup (x ∷ xs) zero    = x
lookup (x ∷ xs) (suc n) = lookup (β™­ xs) n

infixr 5 _++_

_++_ : βˆ€ {a} {A : Set a} β†’ Colist A β†’ Stream A β†’ Stream A
[]       ++ ys = ys
(x ∷ xs) ++ ys = x ∷ β™― (β™­ xs ++ ys)

------------------------------------------------------------------------
-- Equality and other relations

-- xs β‰ˆ ys means that xs and ys are equal.

infix 4 _β‰ˆ_

data _β‰ˆ_ {A : Set a} : Stream A β†’ Stream A β†’ Set a where
  _∷_ : βˆ€ {x y xs ys}
        (x≑ : x ≑ y) (xsβ‰ˆ : ∞ (β™­ xs β‰ˆ β™­ ys)) β†’ x ∷ xs β‰ˆ y ∷ ys

-- x ∈ xs means that x is a member of xs.

infix 4 _∈_

data _∈_ {A : Set a} : A β†’ Stream A β†’ Set a where
  here  : βˆ€ {x   xs}                   β†’ x ∈ x ∷ xs
  there : βˆ€ {x y xs} (x∈xs : x ∈ β™­ xs) β†’ x ∈ y ∷ xs

-- xs βŠ‘ ys means that xs is a prefix of ys.

infix 4 _βŠ‘_

data _βŠ‘_ {A : Set a} : Colist A β†’ Stream A β†’ Set a where
  []  : βˆ€ {ys}                            β†’ []     βŠ‘ ys
  _∷_ : βˆ€ x {xs ys} (p : ∞ (β™­ xs βŠ‘ β™­ ys)) β†’ x ∷ xs βŠ‘ x ∷ ys

------------------------------------------------------------------------
-- Some proofs

setoid : βˆ€ {a} β†’ Set a β†’ Setoid _ _
setoid A = record
  { Carrier       = Stream A
  ; _β‰ˆ_           = _β‰ˆ_ {A = A}
  ; isEquivalence = record
    { refl  = refl
    ; sym   = sym
    ; trans = trans
    }
  }
  where
  refl : Reflexive _β‰ˆ_
  refl {_ ∷ _} = ≑.refl ∷ β™― refl

  sym : Symmetric _β‰ˆ_
  sym (x≑ ∷ xsβ‰ˆ) = ≑.sym x≑ ∷ β™― sym (β™­ xsβ‰ˆ)

  trans : Transitive _β‰ˆ_
  trans (x≑ ∷ xsβ‰ˆ) (y≑ ∷ ysβ‰ˆ) = ≑.trans x≑ y≑ ∷ β™― trans (β™­ xsβ‰ˆ) (β™­ ysβ‰ˆ)

head-cong : {xs ys : Stream A} β†’ xs β‰ˆ ys β†’ head xs ≑ head ys
head-cong (x≑ ∷ _) = x≑

tail-cong : {xs ys : Stream A} β†’ xs β‰ˆ ys β†’ tail xs β‰ˆ tail ys
tail-cong (_ ∷ xsβ‰ˆ) = β™­ xsβ‰ˆ

map-cong : βˆ€ (f : A β†’ B) {xs ys} β†’
           xs β‰ˆ ys β†’ map f xs β‰ˆ map f ys
map-cong f (x≑ ∷ xsβ‰ˆ) = ≑.cong f x≑ ∷ β™― map-cong f (β™­ xsβ‰ˆ)

zipWith-cong : βˆ€ (_βˆ™_ : A β†’ B β†’ C) {xs xsβ€² ys ysβ€²} β†’
               xs β‰ˆ xsβ€² β†’ ys β‰ˆ ysβ€² β†’
               zipWith _βˆ™_ xs ys β‰ˆ zipWith _βˆ™_ xsβ€² ysβ€²
zipWith-cong _βˆ™_ (x≑ ∷ xsβ‰ˆ) (y≑ ∷ ysβ‰ˆ) =
  ≑.congβ‚‚ _βˆ™_ x≑ y≑ ∷ β™― zipWith-cong _βˆ™_ (β™­ xsβ‰ˆ) (β™­ ysβ‰ˆ)

infixr 5 _β‹Ž-cong_

_β‹Ž-cong_ : {xs xsβ€² ys ysβ€² : Stream A} β†’
           xs β‰ˆ xsβ€² β†’ ys β‰ˆ ysβ€² β†’ xs β‹Ž ys β‰ˆ xsβ€² β‹Ž ysβ€²
(x ∷ xsβ‰ˆ) β‹Ž-cong ysβ‰ˆ = x ∷ β™― (ysβ‰ˆ β‹Ž-cong β™­ xsβ‰ˆ)