gens/stream

================== Stream ==================

Types

pub type Stream(a) {
  Stream(head: fn() -> a, tail: fn() -> Stream(a))
}

Constructors

  • Stream(head: fn() -> a, tail: fn() -> Stream(a))

Values

pub fn drop(stream: Stream(a), n: Int) -> Stream(a)

Drops the first n elements from the Stream

pub fn powers() -> Stream(Int) {
  Stream(head: fn() { 1 }, tail: fn() { map(powers(), fn(x) { x * 2 }) })
}
powers() // 1, 2, 4, 8, 16..
|> drop(3)
|> take(5)
// -> [8, 16, 32, 64, 128]
pub fn filter(
  stream: Stream(a),
  pred: fn(a) -> Bool,
) -> Stream(a)

Filters elements from the Stream

pub fn naturals() -> Stream(Int) {
  Stream(head: fn() { 0 }, tail: fn() { map(naturals(), fn(x) { x + 1 }) })
}
filter(naturals(), fn(x) { x % 3 == 0 })
|> take(5)
// -> [0, 3, 6, 9, 12]
pub fn flatten(stream: Stream(List(a))) -> Stream(a)

Flatten a Stream of Lists

let repeat_stream = naturals() |> map(fn(x) { list.repeat(x, x) })
repeat_stream
|> take(5)
// -> [[], [1], [2, 2], [3, 3, 3], [4, 4, 4, 4]]
repeat_stream
|> flatten()
|> take(10)
// -> [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
pub fn fold(stream: Stream(a), f: fn(a, fn() -> b) -> b) -> b

Folds the Stream into a single value using an accumulator

let stream_or = fn(s: Stream(Bool)) -> Bool {
  fold(s, fn(x, next) { x || next() })
}
// If at least one element is True, then the fold ends
// If all elements in the Stream are False, the fold runs infinitely
stream_or(naturals() |> map(fn(x) { x == 10 }))
// -> True
pub fn from_lazy_list(lz: lazy.LazyList(a)) -> Stream(a)

Conversion from LazyList to Stream

let lazy_odds =
  lazy.new()
  |> lazy.filter(int.is_odd)
  |> lazy.map(int.to_string)
let stream_odds = from_lazy_list(lazy_odds)
stream_odds
|> take(5)
// -> ["1", "3", "5", "7", "9"]
pub fn list_zip(
  list: List(a),
  stream: Stream(b),
) -> List(#(a, b))

Zips a list with a Stream

list_zip(["a", "b", "c"], naturals())
// -> [#("a", 0), #("b", 1), #("c", 2)]
pub fn map(stream: Stream(a), f: fn(a) -> b) -> Stream(b)

Maps each element of the Stream

pub fn alt(positive: Bool) -> Stream(Int) {
  Stream(
    head: fn() {
      case positive {
        True -> 1
        False -> -1
      }
    },
    tail: fn() { alt(!positive) },
  )
}
alt(True)
|> map(fn(x) { x * 2 })
|> map(fn(x) { int.to_string(x) <> " oranges" })
|> take(5)
// -> ["2 oranges", "-2 oranges", "2 oranges", "-2 oranges", "2 oranges"]
pub fn merge(
  stream1: Stream(a),
  stream2: Stream(a),
  compare: fn(a, a) -> order.Order,
) -> Stream(a)

Merges two sorted Streams

merge(naturals(), naturals() |> map(fn(x) { x * 2 }), int.compare)
|> take(8)
// -> [0, 0, 1, 2, 2, 3, 4, 4]
pub fn scan(
  stream: Stream(a),
  acc: b,
  f: fn(a, b) -> b,
) -> Stream(b)

Scans the Stream and reconstructs it using an accumulator

pub fn dummy() -> Stream(Nil) {
  Stream(head: fn() { Nil }, tail: dummy)
}
let evens: Stream(Int) = scan(dummy(), 0, fn(_, acc) { acc + 2 })
evens
|> take(5)
// -> [0, 2, 4, 6, 8]
pub fn take(stream: Stream(a), n: Int) -> List(a)

Takes a finite number of elements from the Stream

pub fn ones() -> Stream(Int) {
  Stream(head: fn() { 1 }, tail: ones)
}
ones()
|> take(5)
// -> [1, 1, 1, 1, 1]
pub fn while(
  stream: Stream(a),
  condition: fn(a) -> Bool,
) -> List(a)

Takes elements from the Stream until the condition is false

  naturals()
|> while(fn(x) { x < 5 })
// -> [0, 1, 2, 3, 4]
pub fn zip(
  a_stream: Stream(a),
  b_stream: Stream(b),
) -> Stream(#(a, b))

Zips two Streams togheter

zip(naturals(), drop(naturals(), 5))
|> take(3)
|> [#(0, 5), #(1, 6), #(2, 7)]
Search Document