packages feed

ddc-code-0.4.3.1: tetra/base/Data/Stream.ds

module Data.Stream
export  
{       streamOfList; listOfStream;
        sgenerate; senumFrom; srepeat; scons;
        smap; smapacc;
        sfold; sany;
        stake; stakeWhile; 
        sfilter;
}
import Data.Numeric.Nat
import Data.List
import Data.Maybe
import Data.Tuple
import Data.Array
import Data.Numeric.Bool
import Data.Function
where


-------------------------------------------------------------------------------
-- | Unbounded streams, 
--   wraps a function that produces elements on demand.
data Stream (s a: Data) where
        MkStream : (s -> Step s a) -> s -> Stream s a

data Step (s a: Data) where
        Yield   : a -> s -> Step s a
        Skip    : s -> Step s a 
        Done    : Step s a


-- Conversions ----------------------------------------------------------------
-- | Convert a list to a stream.
streamOfList (xx: List a): Stream (List a) a
 = MkStream step xx
 where  
        step (s1: List a)
         = case s1 of
                Nil       -> Done
                Cons x xs -> Yield x xs


-- | Convert a stream to a list.
listOfStream (ss: Stream s a): List a
 | MkStream f s0 <- ss
 = case f s0 of
        Yield x s1      -> Cons x (listOfStream (MkStream f s1))
        Skip  s1        -> listOfStream (MkStream f s1)
        Done            -> Nil


-- | Load the given number of elements from a stream and write them
--   into a freshly allocated array.
arrayOfStream 
        (n: Nat)         -- ^ Length of result array.
        (d: a)           -- ^ Default element value.
        (ss: Stream s a) -- ^ Stream to evaluate.
        : S (Alloc r1) (Array r1 a)
 = extend r1 using r2 with { Write r2; Alloc r2 } in
   do
        -- Allocate an array of the given maximum size.
        arr     = allocArray [r2] n d

        -- Unstream elements into the array.
        unstreamToArray ss arr 0

        -- Return the completed array.
        arr


-- | Unstream all available elements into the given array.
unstreamToArray
        (ss: Stream s a) (arr: Array r a) (ix: Nat)
        : S (Write r) Unit
 | MkStream f s0  <- ss
 = go s0 0
 where  
        go (s: s) (ix: Nat): S (Write r) Unit
         = case f s of
                Yield x s1
                 -> do  writeArray arr ix x
                        go s1 (ix + 1)

                Skip s1
                 ->     go s1 ix 

                Done
                 ->     ()


-- Constructors ---------------------------------------------------------------
-- | Generate a stream, given a starting value and a stepper function.
sgenerate (x: s) (step: s -> Tup2 s a): Stream s a
 = MkStream step' x
 where  
        step' sA
         = case step sA of
                T2 s' x -> Yield x s'

senumFrom (x: Nat): Stream Nat Nat
 = sgenerate x (λ(s: Nat) -> T2 (s + 1) s)


-- | Create a stream that returns copies of the same value.
srepeat (x: a): Stream a a
 = sgenerate x (λ(s: a) -> T2 s s)


-- | Cons an element to the front of a stream.
scons   (x: a) (ss: Stream s a)
        : Stream (Tup2 s Bool) a
 | MkStream stepA  sA0 <- ss
 = MkStream stepA2 (T2 sA0 True)
 where  
        stepA2 (T2 sA1 True)
         = Yield x (T2 sA1 False)

        stepA2 (T2 sA1 False)
         = case stepA sA1 of
                Yield y sA2 -> Yield y (T2 sA2 False)
                Skip  sA2   -> Skip    (T2 sA2 False)
                Done        -> Done


-- Maps -----------------------------------------------------------------------
-- | Apply a function to every element of a stream.
smap    (f: a -> b) 
        (ss: Stream s a)
        : Stream s b
 | MkStream stepA sA0 <- ss
 = MkStream stepB sA0
 where
        stepB q 
         = case stepA q of
                Yield x sA1     -> Yield (f x) sA1
                Skip sA2        -> Skip sA2
                Done            -> Done


-- Scans ----------------------------------------------------------------------
-- | Like `smap`, but keep a running accumulator as we walk along the stream.
smapacc :  [a b c s: Data]
        .  (a -> b -> Tup2 a c)
        -> a
        -> Stream s b
        -> Stream (Tup2 s a) c

smapacc f z (MkStream fB sB0)
 = MkStream stepC (T2 sB0 z)
 where
        stepC (T2 sB1 xA1)
         = case fB sB1 of
                Yield xB1 sB2 
                 -> case f xA1 xB1 of
                        T2 xA2 xC2
                         -> Yield xC2 (T2 sB2 xA2)
                Skip sB2 -> Skip      (T2 sB2 xA1)
                Done     -> Done


-- Folds ----------------------------------------------------------------------
-- | Fold all the elements from a stream.
sfold   (f: a -> b -> a) 
        (acc: a) 
        ((MkStream step s0): Stream s b)
        : a
 = sconsume f acc step s0


sconsume (f:    a -> b -> a)   (acc:   a) 
         (step: s -> Step s b) (state: s) : a
 = case step state of
        Yield x s'      -> sconsume f (f acc x) step s'
        Skip    s'      -> sconsume f acc       step s'
        Done            -> acc


-- | Check if any of the elements of this stream are true,
--   demanding only the prefix of non-true elements from the stream.
sany [s: Data] (ss: Stream s Bool): Bool
 = sfold or False $ stakeWhile id ss


-- Projections ----------------------------------------------------------------
-- | Take the given number of elements from a stream.
stake   (n: Nat)
        ((MkStream fA sA0): Stream s a)
        : Stream (Tup2 s Nat) a

 = MkStream stepB (T2 sA0 0)
 where  
        stepB (T2 sA ix)
         | ix >= n   = Done
         | otherwise 
         = case fA sA of
                Yield x sA2 -> Yield x (T2 sA2 (ix + 1))
                Skip sA3    -> Skip  (T2 sA3 ix)
                Done        -> Done


-- | Take elements from a stream while they match the given predicate.
stakeWhile 
        (p: a -> Bool) 
        ((MkStream stepA sA0): Stream s a)
        : Stream s a

 = MkStream stepB sA0
 where  
        stepB (q: s)
         = case stepA q of
                Yield x sA1     
                 | p x          -> Yield x sA1
                 | otherwise    -> Done

                Skip sA1        -> Skip    sA1
                Done            -> Done


-- | Take elements from a stream that match the given predicate.
sfilter (p: a -> Bool)
        ((MkStream stepA sA0): Stream s a)
        : Stream s a
 = MkStream stepB sA0
 where
        stepB (q: s)
         = case stepA q of
                Yield x sA1     
                 | p x          -> Yield x sA1
                 | otherwise    -> Skip sA1

                Skip sA1        -> Skip sA1
                Done            -> Done