Stream composition in Elixir

Let’s say we’ve a stream S1 that generates a random number between 1…100.
There is also another stream S2 that also generates a random number between 1…100.

Is it possible to compose S1 and S2 into another Stream S3 such that S3 emits if s1 + s2 is even? Functionality that I am looking for is similar to the one that is in RxJS.

I know the example is made up, but would like to know if streams in Elixir are composable.

Thanks!

There are 2 means of composing streams, you can zip them or concatenate them.

Only of those makes sense in your case.

You can filter the resulting stream into another Stream.

Please take a look at

1 Like
iex(63)> s1 = Stream.repeatedly(fn -> :rand.uniform(100) end)
#Function<54.33009823/2 in Stream.repeatedly/1>
iex(64)> s2 = Stream.repeatedly(fn -> :rand.uniform(100) end)
#Function<54.33009823/2 in Stream.repeatedly/1>
iex(65)> s3 = s1 |> Stream.zip(s2)
#Function<69.33009823/2 in Stream.zip/1>
iex(66)> s4 = Stream.map(s3, fn {a, b} -> a + b end)
#Stream<[
  enum: #Function<69.33009823/2 in Stream.zip/1>,
  funs: [#Function<49.33009823/1 in Stream.map/2>]
]>
iex(67)> s5 = Stream.filter(s4, fn x -> rem(x, 2) == 0 end)
#Stream<[
  enum: #Function<69.33009823/2 in Stream.zip/1>,
  funs: [#Function<49.33009823/1 in Stream.map/2>,
   #Function<41.33009823/1 in Stream.filter/2>]
]>
iex(68)> Enum.take(s2, 5)
[31, 48, 21, 15, 7]
iex(69)> Enum.take(s3, 5)
[{97, 90}, {22, 37}, {11, 100}, {12, 44}, {24, 83}]
iex(71)> Enum.take(s4, 5)
[109, 62, 79, 105, 178]
iex(72)> Enum.take(s5, 5)
[144, 68, 34, 104, 50]
6 Likes

Aha! Both excellent answers. Thank you