module Data.InfiniteSeq
  ( Seq
  , Nat
  , head
  , tail
  , cons
  , elemAt
  , drop
  , toStream
  , toList
  ) where

import Prelude hiding (head, tail, drop)
import Control.Comonad
import Data.Stream (Stream, mkStream)

type Nat = Int
type Seq a = Nat -> a

-- instance Functor ((->) w) where
--   fmap f = (f .)

instance Comonad ((->) Nat) where
  extract   s = s 0
  duplicate s = \i -> drop i s

head :: Seq a -> a
head s   = s 0

tail :: Seq a -> Seq a
tail s   = \i -> s (i + 1)

cons :: a -> Seq a -> Seq a
cons x s = \i -> if i == 0 then x else s (i - 1)

elemAt :: Nat -> Seq a -> a
elemAt i s = s i

drop :: Nat -> Seq a -> Seq a
drop n s = \i -> s (i+n)

toStream :: Seq a -> Stream a
toStream s = mkStream s head tail

toList :: Seq a -> [a]
toList s   = map s [0..]