dwayne/elm-trs2/1.0.0

Logic.Stream

A combination of a list and a lazy list.

type Stream a
= Empty
| Cons a (Stream a)
| Suspend (() -> Stream a)

If you remove the Suspend constructor then you have a list.

type List a
    = Empty
    | Cons a (List a)

If you combine the Cons and Suspend constructors then you have a lazy list.

type LazyList a
    = Empty
    | Cons a (() -> LazyList a)

Normal list streams:

Empty


Cons 3 Empty


Cons 2 (Cons 3 Empty)


Cons 1 (Cons 2 (Cons 3 Empty))

Partial lazy list streams:

Suspend (\_ -> Cons 1 (Cons 2 (Cons 3 Empty)))


Cons 1 (Cons 2 (Suspend (\_ -> Cons 3 (Cons 4 (Suspend (\_ -> Cons 5 Empty))))))

A full lazy list stream:

Suspend (\_ -> Cons 1 (Suspend (\_ -> Cons 2 (Suspend (\_ -> Cons 3 (Suspend (\_ -> Empty)))))))

Create

singleton : a -> Stream a

Create a one element stream.

Combine

append : Stream a -> Stream a -> Stream a

Put two streams together into one stream such that you will be able to eventually access any element from either stream, regardless if the first stream is infinite, the second stream is infinite, or both streams are infinite.

evensLessThan10 =
    Cons 0 (Cons 2 (Cons 4 (Cons 6 (Cons 8 Empty))))


oddsLessThan10 =
    Cons 1 (Cons 3 (Cons 5 (Cons 7 (Cons 9 Empty))))


take 10 (append evensLessThan10 oddsLessThan10) == [ 0, 2, 4, 6, 8, 1, 3, 5, 7, 9 ]


arithmeticProgression a d =
    Cons a <| Suspend (\_ -> arithmeticProgression (a + d) d)


evens =
    arithmeticProgression 0 2


odds =
    arithmeticProgression 1 2


naturals =
    append evens odds


take 10 (append evensLessThan10 odds) == [ 0, 2, 4, 6, 8, 1, 3, 5, 7, 9 ]


take 10 (append evens oddsLessThan10) == [ 0, 1, 3, 5, 7, 9, 2, 4, 6, 8 ]


take 10 naturals == [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

N.B. In the last example, the two infinite streams are completely interleaved. append is the basis upon which it is said that miniKanren uses a complete interleaving search.

appendMap : (a -> Stream b) -> Stream a -> Stream b

Map a function over a stream and append the resulting streams.

repeat n =
    Cons n <| Suspend (\_ -> repeat n)


take 100 (appendMap repeat naturals) == [ 0, 0, 1, 0, 0, 1, 0, 2, 0, 1, 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0 ]


type alias Occurrences =
    Int


statistics : List ( Int, Occurrences )
statistics =
    [ ( 0, 53 )
    , ( 1, 26 )
    , ( 2, 12 )
    , ( 3, 6 )
    , ( 4, 2 )
    , ( 5, 1 )
    ]

N.B. It takes a while to get to each number but each number will eventually be reached, thanks to how append works.

Convert

take : Int -> Stream a -> List a

Take the first n elements of a stream and put them into a list.

toList : Stream a -> List a

Create a list of elements from a stream.

toList evensLessThan10 == [ 0, 2, 4, 6, 8 ]

N.B. It doesn't handle infinite streams. If you know your stream is infinite, use take instead.