{-# LANGUAGE DeriveDataTypeable #-} -- | This implementation of the Stream data type. It's defined similarly to -- other implementation of infinite streams found on hackage, except the -- elements of the stream are strict to prevent some space leaks. module Language.KansasLava.Stream where import Data.Traversable import qualified Data.Foldable as F import Control.Applicative import Control.Monad import Data.Monoid import Prelude hiding (zipWith,zipWith3, repeat) import qualified Data.List as List import Data.Dynamic import Debug.Trace -- | Set the precedence of infix `Cons`. infixr 5 `Cons` -- | A stream is an infinite sequence of values. data Stream a = Cons !a (Maybe (Stream a)) -- ^ Cons takes a head and an optional tail. -- If the tail is empty, then the last value is repeated. deriving (Typeable) instance Show a => Show (Stream a) where show (Cons a opt_as) = show a ++ " " ++ maybe "" show opt_as instance Applicative Stream where pure a = a `Cons` Nothing (h1 `Cons` t1) <*> (h2 `Cons` t2) = h1 h2 `Cons` (t1 `opt_ap` t2) where Nothing `opt_ap` Nothing = Nothing Nothing `opt_ap` (Just x) = Just (pure h1 <*> x) (Just f) `opt_ap` Nothing = Just (f <*> pure h2) (Just f) `opt_ap` (Just x) = Just (f <*> x) instance Functor Stream where fmap f (a `Cons` opt_as) = f a `Cons` maybe Nothing (Just . fmap f) opt_as -- | Lift a value to be a constant stream. --repeat :: a -> Stream a --repeat a = a `Cons` repeat a -- | Zip two streams together. zipWith :: (a -> b -> c) -> Stream a -> Stream b -> Stream c zipWith f xs ys = f <$> xs <*> ys -- | Zip three streams together. zipWith3 :: (a -> b -> c -> d) -> Stream a -> Stream b -> Stream c -> Stream d zipWith3 f xs ys zs = f <$> xs <*> ys <*> zs -- | Convert a list to a stream. If the list is finite, then the last element of -- the stream will be an error. fromFiniteList :: [a] -> a -> Stream a fromFiniteList (x : xs) end = x `Cons` (Just (fromFiniteList xs end)) fromFiniteList [] end = end `Cons` Nothing fromList :: [a] -> Stream a fromList xs = fromFiniteList xs (error "found end of infinite list") -- | Convert a Stream to a lazy list. toList :: Stream a -> [a] toList (x `Cons` opt_xs) = x : maybe (List.repeat x) toList opt_xs instance F.Foldable Stream where foldMap f (a `Cons` opt_as) = f a `mappend` maybe (F.foldMap f (a `Cons` opt_as)) (F.foldMap f) opt_as instance Traversable Stream where traverse f (a `Cons` opt_as) = Cons <$> f a <*> maybe (pure Nothing) (\ as -> Just <$> traverse f as) opt_as observeStream :: (Show a) => String -> Stream a -> Stream a observeStream nm (Cons a rest) = trace (show (nm,a)) $ Cons a $ case rest of Nothing -> trace (show (nm,".")) $ Nothing Just xs -> Just $ observeStream nm xs