SlideShare a Scribd company logo
Hand-Toss a Stream
(Lazy List)
in C#
Dhaval Dalal
https://dhavaldalal.wordpress.com
@softwareartisan
Implementing Lazy List
IEnumerable<int> Naturals(int @from) {

for (var i = @from; true ; i++) {

yield return i;

}

}

Naturals(0)
.Take(3)
.ForEach(Console.WriteLine); // 0 1 2
Using generators
This is the idiomatic approach.
There is yet another one as well.
Implementing Lazy List
Using Lambda
Wrap the tail of the
list in a closure.
1 ?
Implementing Lazy List
Using Lambda
Wrap the tail of the
list in a closure.
When we need the result
evaluate the tail by
invoking the closure.
Evaluate
tail
1 ?
1 *
2 ?
Implementing Lazy List
Using Lambda
Wrap the tail of the
list in a closure.
When we need the result
evaluate the tail by
invoking the closure.
Additionally for
performance - Cache or
Memoize the closure
output.
Evaluate
tail
1 ?
1 *
2 ?
Implementing Lazy List
Using Lambda
Wrap the tail of the
list in a closure.
When we need the result
evaluate the tail by
invoking the closure.
Additionally for
performance - Cache or
Memoize the closure
output.
Evaluate
tail
1 ?
1 *
2 ?
Implementing Lazy List
Stream implementation shown in these slides is available on:
https://github.com/CodeJugalbandi/FunctionalProgramming/blob/master/melodies/lazy_sequences/Stream.cs
Immutable Stream with
eager Head & lazy Tail
sealed class Stream<T> {

private readonly T head;

private readonly Func<Stream<T>> tail;



public Stream(T head, Func<Stream<T>> tail) {

this.head = head;

this.tail = tail;

}

public T Head {

get => head;

}

public Stream<T> Tail {

get => tail(); // Need Memoization (for Perf)

}

public override string ToString() =>
$"Stream<{typeof(T)}>({head}, ?)";

}
Immutable Stream with
eager Head & lazy Tail
sealed class Stream<T> {

private readonly T head;

private readonly Lazy<Stream<T>> tail;



public Stream(T head, Lazy<Stream<T>> tail) {

this.head = head;

this.tail = tail;

}

public T Head {

get => head;

}

public Stream<T> Tail {

get => tail.Value; // Cached after first eval

}

public override string ToString() =>
$"Stream<{typeof(T)}>({head}, ?)";

}
Immutable Stream with
eager Head & lazy Tail
var empty = new Stream<int>(0, null);

Console.WriteLine(empty); // Stream<System.Int32>(0, ?)

Console.WriteLine(empty.Head); // 0

Console.WriteLine(empty.Tail);



var singleton = new Stream<int>(1, new Lazy<Stream<int>>(() => empty));

Console.WriteLine(singleton); // Stream<System.Int32>(1, ?)

Console.WriteLine(singleton.Head); // 1

Console.WriteLine(singleton.Tail); // Stream<System.Int32>(0, ?)



var couple = new Stream<int>(2, new Lazy<Stream<int>>(() => singleton));

Console.WriteLine(couple); // Stream<System.Int32>(2, ?)

Console.WriteLine(couple.Head); // 2

Console.WriteLine(couple.Tail); // Stream<System.Int32>(1, ?)

Console.WriteLine(couple.Tail.Tail); // Stream<System.Int32>(0, ?)

Console.WriteLine(couple.Tail.Tail.Tail);
As Streams are immutable
we can structurally share
the earlier stream.
Boom!
Boom!
Introduce Empty Stream
sealed class Stream<T> {

public static readonly Stream<T> Empty
= new Stream<T>(default(T), null);

private readonly T head;

private readonly Lazy<Stream<T>> tail;

public Stream(T head, Lazy<Stream<T>> tail) { … }

public T Head { … }

public Stream<T> Tail { … }

public bool IsEmpty {

get => tail == null;

}

public override string ToString() {

if (IsEmpty) 

return "Empty";



return $"Stream<{typeof(T)}>({head}, ?)";

}

}
Introduce Empty Stream
var empty = Stream<int>.Empty;

Console.WriteLine(empty); // Empty

Console.WriteLine(empty.IsEmpty); // True



var singleton =
new Stream<int>(1, new Lazy<Stream<int>>(() => empty));

Console.WriteLine(singleton); // Stream(1, ?)

Console.WriteLine(singleton.IsEmpty); // False



var couple =
new Stream<int>(2, new Lazy<Stream<int>>(() => singleton));

Console.WriteLine(couple); // Stream(2, ?)

Console.WriteLine(couple.IsEmpty); // False
Doing Side-effects
sealed class Stream<T> {
…
…

public void ForEach(Action<T> action) {

if (IsEmpty)

return;


action(Head);

Tail.ForEach(action);

}

}
var empty = Stream<int>.Empty;

empty.ForEach(Console.WriteLine); // Prints Nothing

var stream = new Stream<int>(2, new Lazy<Stream<int>>(new
Stream<int>(1, new Lazy<Stream<int>>(() => empty))));

stream.ForEach(Console.WriteLine); // 2 1
Consing to Stream
sealed class Stream<T> {

…
…

// Cons using +

public static Stream<T> operator + (Stream<T> s, T element) => 

new Stream<T>(element, new Lazy<Stream<T>>(() => s));

}
var stream = Stream<int>.Empty + 1 + 2;

Console.WriteLine(stream); // Stream(2, ?)

Console.WriteLine(stream.Head); // 2

Console.WriteLine(stream.Tail); // Stream(1, ?)


stream.ForEach(Console.WriteLine); // 2 1
Prepend (Cons)
Append to Stream
sealed class Stream<T> {
…

// Append using +

public static Stream<T> operator + (T element, Stream<T> s) => 

new Stream<T>(element,
new Lazy<Stream<T>>(() => s.IsEmpty ? Stream<T>.Empty : s));

}
var stream = 1 + Stream<int>.Empty;

stream.ForEach(Console.WriteLine); // 1



var stream = 1 + (2 + (3 + (4 + Stream<int>.Empty)));

stream.ForEach(Console.WriteLine); // 1 2 3 4
sealed class Stream<T> {
…
public static Stream<R> Of<R>(params R[] rs) {

var stream = Stream<R>.Empty;

var indices = rs.Length - 1;

for (var i = indices; i >= 0; i--) {

stream = stream + rs[i];

}

return stream;

}

}
Stream<int>.Of<int>()
.ForEach(Console.WriteLine); // Prints Nothing
Stream<int>.Of(1, 2, 3, 4)
.ForEach(Console.WriteLine); // 1 2 3 4
Construct a Stream
from few elements
Concat another Stream
sealed class Stream<T> {

…

public static Stream<T> operator + (Stream<T> @this,
Stream<T> other) {
if (@this.IsEmpty)

return other;



return new Stream<T>(@this.Head,
new Lazy<Stream<T>>(() => @this.Tail + other));

}
}
var concat1 = Stream<char>.Empty + Stream<char>.Of('a', 'b');

concat1.ForEach(Console.Write); // ab



var concat2 = Stream<char>.Of('a', 'b') + Stream<char>.Empty;

concat2.ForEach(Console.Write); // ab



var concat3 = Stream<char>.Of('a', 'b') + Stream<char>.Of('c', 'd', 'e');

concat3.ForEach(Console.Write); // abcde
sealed class Stream<T> {

…
public Stream<T> Take(int howMany) {

if (IsEmpty || howMany <= 0)

return Stream<T>.Empty;



return new Stream<T>(Head,
new Lazy<Stream<T>>(() => Tail.Take(howMany - 1)));

}

}
Stream<int>.Empty
.Take(2).ForEach(Console.WriteLine); // Prints Nothing

Stream<int>.Of(1, 2, 3, 4)
.Take(2).ForEach(Console.WriteLine); // 1 2

Stream<int>.Of(1, 2, 3, 4)
.Take(12).ForEach(Console.WriteLine); // 1 2 3 4

Stream<int>.Of(1, 2, 3, 4)
.Take(0).ForEach(Console.WriteLine); // Prints Nothing
Take few elements
sealed class Stream<T> {

…
public Stream<T> Drop(int howMany) {

if (IsEmpty || howMany <= 0)

return this;



return Tail.Drop(howMany - 1);

}

}
Stream<int>.Empty
.Drop(2).ForEach(Console.WriteLine); // Prints Nothing

Stream<int>.Of(1, 2, 3, 4)
.Drop(2).ForEach(Console.WriteLine); // 3 4

Stream<int>.Of(1, 2, 3, 4)
.Drop(20).ForEach(Console.WriteLine); // Prints Nothing

Stream<int>.Of(1, 2, 3, 4)
.Drop(0).ForEach(Console.WriteLine); // 1 2 3 4
Drop few elements
sealed class Stream<T> {

…
…
public static Stream<R> Generate<R>(Func<R> fn) => 

new Stream<R>(fn(), new Lazy<Stream<R>>(() => Generate(fn)));
}
var random = new Random();

Stream<int>.Generate(() => random.Next(100, 150))
.Take(4)
.ForEach(Console.WriteLine);
// Prints 4 random numbers bet [100, 150)
Construct a Stream
using lambda - 1
sealed class Stream<T> {

…
…
public static Stream<R> Iterate<R>(R initial, Func<R, R> fn) => 

new Stream<R>(initial,
new Lazy<Stream<R>>(() => Iterate(fn(initial), fn)));

}
Stream<int>.Iterate(9, x => x + 2)
.Take(4)
.ForEach(Console.WriteLine); // 9 11 13 15
Construct a Stream
using lambda - 2
sealed class Stream<T> {

…
…
public void Deconstruct(out T first, out Stream<T> rest) {

if (IsEmpty) 

throw new ArgumentException("Collection is Empty!");



first = Head;

rest = Drop(1);

}

}
var (head, rest) = Stream<int>.Of(1, 2, 3, 4);

Console.WriteLine("Head = " + head); // 1

Console.WriteLine("Rest = " + rest); // Stream(2, ?)
Deconstruct a Stream
sealed class Stream<T> {

…
public void Deconstruct(out T first, out Stream<T> rest) {

if (IsEmpty) 

throw new ArgumentException("Collection is Empty!");



first = Head;

rest = Drop(1);

}

public void Deconstruct(out T first, out T second,
out Stream<T> rest) =>
(first, (second, rest)) = this; 

}
var (head, second, rest) = Stream<int>.Of(1, 2, 3, 4);
Console.WriteLine("Head = " + head); // 1
Console.WriteLine("Second = " + second); // 2
Console.WriteLine("Rest = " + rest); // Stream(2, ?)
Deconstruct a Stream
sealed class Stream<T> {

…
public void Deconstruct(out T first, out T second,
out Stream<T> rest) =>

(first, (second, rest)) = this;



public void Deconstruct(out T first, out T second, out T third,
out Stream<T> rest) =>

(first, second, (third, rest)) = this;

}
var (head, second, third, rest) = Stream<int>.Of(1, 2, 3, 4);

Console.WriteLine("Head = " + head); // 1

Console.WriteLine("Second = " + second); // 2

Console.WriteLine("Third = " + third); // 3

Console.WriteLine("Rest = " + rest); // Stream(4, ?)
Deconstruct a Stream
Transform each element
sealed class Stream<T> {

…
…

public Stream<R> Select<R>(Func<T, R> fn) {

if (IsEmpty)

return Stream<R>.Empty;



return new Stream<R>(fn(Head),
new Lazy<Stream<R>>(() => Tail.Select(fn)));

}

}
var empty = Stream<int>.Empty;
Console.WriteLine(empty.Select(x => x * x)); // Prints Nothing
var stream = Stream<int>.Of(1, 2);

Console.WriteLine(stream.Select(x => x * x)); // 1 4
Filtering the Stream
sealed class Stream<T> {

…

public Stream<T> Where(Predicate<T> pred) {

if (IsEmpty)

return Stream<T>.Empty;



if (pred(Head)) 

return new Stream<T>(Head,
new Lazy<Stream<T>>(() => Tail.Where(pred)));



return Tail.Where(pred);

}

}
var empty = Stream<int>.Empty;
Console.WriteLine(empty.Where(x => x < 2)); // Prints Nothing
var stream = Stream<int>.Of(1, 2);

Console.WriteLine(stream.Where(x => x < 2)); // 1
Flatmap the Stream
sealed class Stream<T> {
…

public Stream<T> SelectMany(Func<T, Stream<R>> fn) {

if (IsEmpty)

return Stream<R>.Empty;



return fn(Head) + Tail.SelectMany(fn);

}

}
Stream<char>.Of('a', 'b')

.SelectMany(c => Stream<int>.Of(1, 2).Select(n => (c, n)))

.ForEach(t => Console.Write(t)); // (a, 1)(a, 2)(b, 1)(b, 2)



Stream<int>.Empty.SelectMany(c => Stream<int>.Of(1, 2).Select(n => (c, n)))

.ForEach(t => Console.Write(t)); // Prints Nothing
Reverse
sealed class Stream<T> {

…
…

public Stream<T> Reverse() {

Stream<T> Reverse0(Stream<T> acc, Stream<T> source) {

if (source.IsEmpty)

return acc;



return Reverse0(acc + source.Head, source.Tail);

}

return Reverse0(Stream<T>.Empty, this);

}

}
Stream<char>.Of('a', 'b', ‘c')
.Reverse().ForEach(Console.Write); // cba


Stream<int>.Empty
.Reverse().ForEach(Console.WriteLine); // Prints Nothing
Take while
predicate holds
sealed class Stream<T> {

…

public Stream<T> TakeWhile(Predicate<T> pred) {

if (IsEmpty)

return Stream<T>.Empty;



if (pred(Head))

return Head + Tail.TakeWhile(pred);



return Stream<T>.Empty;

}

}
Stream<char>.Of('a', 'a', 'b', 'c').TakeWhile(c => c == 'a')

.ForEach(Console.Write); // aa



Stream<char>.Of('a', 'a', 'b', 'c').TakeWhile(c => c == 'b')

.ForEach(Console.Write); // Prints Nothing
sealed class Stream<T> {

…

public Stream<T> DropWhile(Predicate<T> pred) {

if (IsEmpty)

return Stream<T>.Empty;



if (pred(Head))

return Tail.DropWhile(pred);



return this;

}

}
Stream<char>.Of('a', 'a', 'b', 'c').DropWhile(c => c == 'a')

.ForEach(Console.Write); // bc



Stream<char>.Of('a', 'a', 'b', 'c').DropWhile(c => c == 'b')

.ForEach(Console.Write); // aabc
Drop while
predicate holds
sealed class Stream<T> {

…

public U Aggregate<U>(U identity, Func<U, T, U> func) {

if (IsEmpty)

return identity;



return Tail.Aggregate(func(identity, Head), func);

}

}
var sum1 = Stream<int>.Of(1, 2, 3, 4)
.Aggregate(0, (acc, elem) => acc + elem);

Console.WriteLine($"sum = {sum1}"); // 10

var sum2 = Stream<int>.Of<int>()
.Aggregate(0, (acc, elem) => acc + elem); 

Console.WriteLine($"sum = {sum2}"); // 0
Aggregate or Reduce
sealed class Stream<T> {

…

public bool All(Predicate<T> pred) {

bool All0(bool accumulator, Stream<T> stream) {

if (stream.IsEmpty || accumulator == false)

return accumulator;



return All0(accumulator && pred(stream.Head), stream.Tail);

}

return All0(true, this);

}

}
Console.WriteLine(Stream<int>.Of<int>().All(x => x % 2 == 0));
// True

Console.WriteLine(Stream<int>.Of<int>(2, 4).All(x => x % 2 == 0));
// True

Console.WriteLine(Stream<int>.Of<int>(1, 2, 4).All(x => x % 2 == 0));
// False
All Don’t evaluate the entire
Stream, short-circuit if we
already determined
negation.
sealed class Stream<T> {

…

public bool Any(Predicate<T> pred) {

bool Any0(bool accumulator, Stream<T> stream) {

if (stream.IsEmpty || accumulator == true)

return accumulator;



return Any0(accumulator || pred(stream.Head), stream.Tail);

}

return Any0(false, this);

}

}
Console.WriteLine(Stream<int>.Of<int>().Any(x => x % 2 == 0));
// False

Console.WriteLine(Stream<int>.Of<int>(2, 4).Any(x => x % 2 == 0));
// True

Console.WriteLine(Stream<int>.Of<int>(1, 2, 4).Any(x => x % 2 == 0));
// True

Console.WriteLine(Stream<int>.Of<int>(1, 3).Any(x => x % 2 == 0));
// False
Any Don’t evaluate the entire
Stream, short-circuit if we
already determined
affirmation.
sealed class Stream<T> {

…

public Stream<T> Scan(U identity, Func<U, T, U> func) {

if (IsEmpty)

return Stream<T>.Empty;



U newHead = func(identity, Head);

return newHead + Tail.Scan(newHead, func);

}

}
// Prints running sum

Stream<int>.Of(1, 2, 3, 4)
.Scan(0, (acc, elem) => acc + elem)
.ForEach(Console.WriteLine); // 1 3 6 10

Stream<int>.Of<int>()
.Scan(0, (acc, elem) => acc + elem)
.ForEach(Console.WriteLine); // Prints Nothing
Scan
Zip two Streams
sealed class Stream<T> {

…

public Stream<(T,U)> Zip<U>(Stream<U> that) {

if (this.IsEmpty || that.IsEmpty)

return Stream<(T,U)>.Empty;



return (this.Head, that.Head) + this.Tail.Zip(that.Tail);

}

}
Stream<char>.Of('a', 'b').Zip(Stream<int>.Of(1, 2))

.ForEach(t => Console.Write(t)); // (a, 1)(b, 2)



Stream<char>.Of('a', 'b').Zip(Stream<int>.Empty)

.ForEach(t => Console.Write(t)); // Prints Nothing



Stream<int>.Empty.Zip(Stream<char>.Of('a', 'b'))

.ForEach(t => Console.Write(t)); // Prints Nothing
Zip with function
sealed class Stream<T> {

…

public Stream<R> ZipWith<U, R>(Stream<U> that, Func<T, U, R> fn) {

if (this.IsEmpty || that.IsEmpty)

return Stream<R>.Empty;



return fn(this.Head, that.Head) +
this.Tail.ZipWith(that.Tail, fn);

}

}
var numbers = Stream<int>.Of(1, 2, 3);

numbers.ZipWith(numbers, (n1, n2) => n1 * n2)

.ForEach(Console.WriteLine); // 1 4 9



numbers.ZipWith(Stream<int>.Empty, (n1, n2) => n1 * n2)

.ForEach(Console.WriteLine); // Prints Nothing



Stream<int>.Empty.ZipWith(numbers, (n1, n2) => n1 * n2)

.ForEach(Console.WriteLine); // Prints Nothing
Splitsealed class Stream<T> {

…

public (Stream<T>, Stream<T>) Split(Predicate<T> pred) {

(Stream<T>, Stream<T>) Split0(Stream<T> yesAcc,
Stream<T> noAcc,
Stream<T> source) {

if (source.IsEmpty) 

return (yesAcc.Reverse(), noAcc.Reverse());



var elem = source.Head;

if (pred(elem))

return Split0(yesAcc + elem, noAcc, source.Tail);

else

return Split0(yesAcc, noAcc + elem, source.Tail);

} 

return Split0(Stream<T>.Empty, Stream<T>.Empty, this);

}

}
var (evens, odds) = Stream<int>.Iterate(0, x => x + 1).Take(10)
.Split(x => x % 2 == 0);

evens.ForEach(Console.Write); // 02468

odds.ForEach(Console.Write); // 13579
To List
sealed class Stream<T> {

…
public List<T> ToList() {

var result = new List<T>();

ForEach(result.Add);

return result;

}

}
var list = Stream<int>.Iterate(1, x => x + 1)
.Take(4)
.ToList();

foreach (var item in list) {

Console.WriteLine(item);

}
Find first 6 primes using the Sieve of
Eratosthenes
Hint: Use Stream created earlier
http://world.mathigon.org/Prime_Numbers
Sieve
Stream<int> From(int start) =>
Stream<int>.Iterate(start, x => x + 1);

Stream<int> Sieve(Stream<int> s) {

var first = s.Head;

var rest = s.Tail.Where(n => n % first != 0);

return new Stream<int>(first,
new Lazy<Stream<int>>(() => rest));

}



var primes = Sieve(From(2)).Take(6)
primes.ToList() // [2, 3, 5, 7, 11, 13]
First 10 Fibonacci Nos.
Write a function fibonacci which consumes an
integer and produces that many numbers in the
fibonacci series.
For Example: fibonacci(10) produces
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Provide Solutions
Using Generator
Using IEnumerable
Using Stream that we developed
IEnumerable<int> Fibonacci(int howMany) {
var (first, second) = (0, 1);

for (var i = 0; i < howMany; i++) {

yield return first;

(first, second) = (second, first + second);

}

}



Fibonacci(10).ToList();

// [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
First 10 Fibonacci Nos.
Using Generator
IEnumerable<int> Fibonacci(int howMany) {
return IEnumerableExtensions.Iterate<(int, int)>((0, 1), tuple => {

var (first, second) = tuple;

var next = first + second;

return (second, next);

})

.Select(tuple => {

var (first, second) = tuple;

return first;

})

.Take(howMany);

}
Fibonacci(10).ToList();
// [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
First 10 Fibonacci Nos.
Using IEnumerable
Definition as suggested by Christopher Grande
First 10 Fibonacci Nos.
Using Stream
https://www.haskell.org/tutorial/functions.html
var seed = From(0).Take(2);

// Start with seed elements 0 and 1

Fibonacci(seed)

.Take(10)

.ForEach(Console.WriteLine);
// 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
Stream<int> Fibonacci(Stream<int> s) {

var next = s.Zip(s.Tail).Select(tuple => {

var (first, second) = tuple;

return first + second;

});

return new Stream<int>(s.Head,
new Lazy<Stream<int>>(() => Fibonacci(s + next.Head)));

}
Prime Counts
Using Lazy Lists, write a
program that counts number of
primes up to a given number.
At every power of 10, it should
emit the count of primes
obtained thus far. The table
shows the output until 10
10
Implement this using:
Using Stream we developed earlier.
Using IEnumerable
Hint: Write an extension method Scan
on IEnumerable
i/p count
10 4
10
2 25
10
3 168
10
4 1,229
10
5 9,592
10
6 78,498
10
7 6,64,579
10
8 57,61,455
10
9 5,08,47,534
10
10 45,50,52,511
class Streams {

public static Stream<int> Range(int start, int count) {

if (count < 0)

throw new ArgumentOutOfRangeException($"{count}");



return Stream<int>.Iterate(start, x => x + 1).Take(count);

} 

}

Streams.Range(1, 5).ForEach(Console.WriteLine);
// 1 2 3 4 5
Prime Counts using IEnumerable
First, write our own Range
Prime Counts Using Stream
Stream<(int, int)> PrimeCount(int howManyPowerOf10) {

bool IsPrime(int x) => Streams.Range(2, x)
.Where(n => n < x)
.All(n => x % n != 0);


return Stream<int>.Iterate(2, x => x + 1)

.TakeWhile(x => x <= Math.Pow(10, howManyPowerOf10))

.Select(x => (x, IsPrime(x)))

.Scan((0, 0), (acc, tuple) => {

var (x, isPrime) = tuple;

var (_, count) = acc;

return isPrime ? (x, count + 1): (x, count);

})

.Where(tuple => {

var (x, _) = tuple;

return Streams.Range(1, howManyPowerOf10)

.Any(n => Math.Pow(10, n) == x);

});

}
PrimeCount(3).ForEach(t => Console.WriteLine(t));
(10, 4), (100, 25), (1000, 168)
Prime Counts using IEnumerable
First, write our own Scan
static class IEnumerableExtensions {
public static IEnumerable<U> Scan<T, U>(this IEnumerable<T> @this,
U initial, Func<U, T, U> fn) {

IEnumerable<U> ScannedEnumerable() {

var acc = seed;

foreach (var item in @this) {

acc = fn(acc, item);

yield return acc;

} 

if (@this == null)

throw new ArgumentNullException("Require non-null list!");

if (fn == null)

throw new ArgumentNullException("Require non-null function!”);

return ScannedEnumerable();

}
}
Prime Counts using IEnumerable
IEnumerable<(int, int)> PrimeCount(int howManyPowerOf10) {

bool IsPrime(int x) => Enumerable.Range(2, x)
.Where(n => n < x)
.All(n => x % n != 0);


return IEnumerableExtensions.Iterate(2, x => x + 1)

.TakeWhile(x => x <= Math.Pow(10, howManyPowerOf10))

.Select(x => (x, IsPrime(x)))

.Scan((0, 0), (acc, tuple) => {

var (x, isPrime) = tuple;

var (_, count) = acc;

return isPrime ? (x, count + 1): (x, count);

})

.Where(tuple => {

var (x, _) = tuple;

return Enumerable.Range(1, howManyPowerOf10)

.Any(n => Math.Pow(10, n) == x);

});

}
PrimeCount(3).ForEach(t => Console.WriteLine(t));
(10, 4), (100, 25), (1000, 168)
Drawbacks of this
Stream Implementation
As C# compiler does not support Tail-
Recursion, all the APIs that are
implemented recursively will cause a
stack blow-up at some point for large
values of stream.
Even-though it uses caching of tail
using Lazy<T>, this Stream is not
performant like IEnumerable! This is
because the recursive APIs don’t run in
constant stack space.
But still its a good
mental exercise to create
streams from first
principles!
Thank-you!

More Related Content

What's hot (20)

Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Mario Fusco
 
JavaScript Functions
JavaScript FunctionsJavaScript Functions
JavaScript Functions
Colin DeCarlo
 
Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1
José Paumard
 
If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are Wrong
Mario Fusco
 
Jumping-with-java8
Jumping-with-java8Jumping-with-java8
Jumping-with-java8
Dhaval Dalal
 
Java 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forwardJava 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forward
Mario Fusco
 
LinkedIn TBC JavaScript 100: Functions
 LinkedIn TBC JavaScript 100: Functions LinkedIn TBC JavaScript 100: Functions
LinkedIn TBC JavaScript 100: Functions
Adam Crabtree
 
Swiss army knife Spring
Swiss army knife SpringSwiss army knife Spring
Swiss army knife Spring
Mario Fusco
 
Java 8: the good parts!
Java 8: the good parts!Java 8: the good parts!
Java 8: the good parts!
Andrzej Grzesik
 
Refactoring to Java 8 (Devoxx BE)
Refactoring to Java 8 (Devoxx BE)Refactoring to Java 8 (Devoxx BE)
Refactoring to Java 8 (Devoxx BE)
Trisha Gee
 
Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8
RichardWarburton
 
Leveraging Completable Futures to handle your query results Asynchrhonously
Leveraging Completable Futures to handle your query results AsynchrhonouslyLeveraging Completable Futures to handle your query results Asynchrhonously
Leveraging Completable Futures to handle your query results Asynchrhonously
David Gómez García
 
JavaScript Functions
JavaScript FunctionsJavaScript Functions
JavaScript Functions
Brian Moschel
 
Sneaking inside Kotlin features
Sneaking inside Kotlin featuresSneaking inside Kotlin features
Sneaking inside Kotlin features
Chandra Sekhar Nayak
 
Reactive Programming for a demanding world: building event-driven and respons...
Reactive Programming for a demanding world: building event-driven and respons...Reactive Programming for a demanding world: building event-driven and respons...
Reactive Programming for a demanding world: building event-driven and respons...
Mario Fusco
 
Java9 Beyond Modularity - Java 9 más allá de la modularidad
Java9 Beyond Modularity - Java 9 más allá de la modularidadJava9 Beyond Modularity - Java 9 más allá de la modularidad
Java9 Beyond Modularity - Java 9 más allá de la modularidad
David Gómez García
 
Booting into functional programming
Booting into functional programmingBooting into functional programming
Booting into functional programming
Dhaval Dalal
 
Core Java - Quiz Questions - Bug Hunt
Core Java - Quiz Questions - Bug HuntCore Java - Quiz Questions - Bug Hunt
Core Java - Quiz Questions - Bug Hunt
CodeOps Technologies LLP
 
Python Programming Essentials - M8 - String Methods
Python Programming Essentials - M8 - String MethodsPython Programming Essentials - M8 - String Methods
Python Programming Essentials - M8 - String Methods
P3 InfoTech Solutions Pvt. Ltd.
 
Java script – basic auroskills (2)
Java script – basic   auroskills (2)Java script – basic   auroskills (2)
Java script – basic auroskills (2)
BoneyGawande
 
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Mario Fusco
 
JavaScript Functions
JavaScript FunctionsJavaScript Functions
JavaScript Functions
Colin DeCarlo
 
Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1
José Paumard
 
If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are Wrong
Mario Fusco
 
Jumping-with-java8
Jumping-with-java8Jumping-with-java8
Jumping-with-java8
Dhaval Dalal
 
Java 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forwardJava 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forward
Mario Fusco
 
LinkedIn TBC JavaScript 100: Functions
 LinkedIn TBC JavaScript 100: Functions LinkedIn TBC JavaScript 100: Functions
LinkedIn TBC JavaScript 100: Functions
Adam Crabtree
 
Swiss army knife Spring
Swiss army knife SpringSwiss army knife Spring
Swiss army knife Spring
Mario Fusco
 
Refactoring to Java 8 (Devoxx BE)
Refactoring to Java 8 (Devoxx BE)Refactoring to Java 8 (Devoxx BE)
Refactoring to Java 8 (Devoxx BE)
Trisha Gee
 
Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8Pragmatic functional refactoring with java 8
Pragmatic functional refactoring with java 8
RichardWarburton
 
Leveraging Completable Futures to handle your query results Asynchrhonously
Leveraging Completable Futures to handle your query results AsynchrhonouslyLeveraging Completable Futures to handle your query results Asynchrhonously
Leveraging Completable Futures to handle your query results Asynchrhonously
David Gómez García
 
JavaScript Functions
JavaScript FunctionsJavaScript Functions
JavaScript Functions
Brian Moschel
 
Reactive Programming for a demanding world: building event-driven and respons...
Reactive Programming for a demanding world: building event-driven and respons...Reactive Programming for a demanding world: building event-driven and respons...
Reactive Programming for a demanding world: building event-driven and respons...
Mario Fusco
 
Java9 Beyond Modularity - Java 9 más allá de la modularidad
Java9 Beyond Modularity - Java 9 más allá de la modularidadJava9 Beyond Modularity - Java 9 más allá de la modularidad
Java9 Beyond Modularity - Java 9 más allá de la modularidad
David Gómez García
 
Booting into functional programming
Booting into functional programmingBooting into functional programming
Booting into functional programming
Dhaval Dalal
 
Java script – basic auroskills (2)
Java script – basic   auroskills (2)Java script – basic   auroskills (2)
Java script – basic auroskills (2)
BoneyGawande
 

Similar to Creating Lazy stream in CSharp (20)

Lowering in C#: What really happens with your code?, from NDC Oslo 2019
Lowering in C#: What really happens with your code?, from NDC Oslo 2019Lowering in C#: What really happens with your code?, from NDC Oslo 2019
Lowering in C#: What really happens with your code?, from NDC Oslo 2019
David Wengier
 
NetPonto - The Future Of C# - NetConf Edition
NetPonto - The Future Of C# - NetConf EditionNetPonto - The Future Of C# - NetConf Edition
NetPonto - The Future Of C# - NetConf Edition
Paulo Morgado
 
15. Streams Files and Directories
15. Streams Files and Directories 15. Streams Files and Directories
15. Streams Files and Directories
Intro C# Book
 
Tuga IT 2018 Summer Edition - The Future of C#
Tuga IT 2018 Summer Edition - The Future of C#Tuga IT 2018 Summer Edition - The Future of C#
Tuga IT 2018 Summer Edition - The Future of C#
Paulo Morgado
 
Concurrent Collections Object In Dot Net 4
Concurrent Collections Object In Dot Net 4Concurrent Collections Object In Dot Net 4
Concurrent Collections Object In Dot Net 4
Neeraj Kaushik
 
F# in the enterprise
F# in the enterpriseF# in the enterprise
F# in the enterprise
7sharp9
 
csharp dot net codes for practical examination
csharp dot net codes for practical examinationcsharp dot net codes for practical examination
csharp dot net codes for practical examination
SanikaPatil68377
 
Collection
CollectionCollection
Collection
Gayathri Ganesh
 
final project for C#
final project for C#final project for C#
final project for C#
Benjamin Fulker
 
Multi core programming 2
Multi core programming 2Multi core programming 2
Multi core programming 2
Robin Aggarwal
 
Oops pramming with examples
Oops pramming with examplesOops pramming with examples
Oops pramming with examples
Syed Khaleel
 
Csharp_Chap13
Csharp_Chap13Csharp_Chap13
Csharp_Chap13
Mohamed Krar
 
C# Starter L04-Collections
C# Starter L04-CollectionsC# Starter L04-Collections
C# Starter L04-Collections
Mohammad Shaker
 
C# labprograms
C# labprogramsC# labprograms
C# labprograms
Jafar Nesargi
 
How to capture a variable in C# and not to shoot yourself in the foot
How to capture a variable in C# and not to shoot yourself in the footHow to capture a variable in C# and not to shoot yourself in the foot
How to capture a variable in C# and not to shoot yourself in the foot
Sofia Fateeva
 
How to capture a variable in C# and not to shoot yourself in the foot
How to capture a variable in C# and not to shoot yourself in the footHow to capture a variable in C# and not to shoot yourself in the foot
How to capture a variable in C# and not to shoot yourself in the foot
PVS-Studio
 
What's new in c#7
What's new in c#7What's new in c#7
What's new in c#7
Kyrylo Bezpalyi
 
using System.docx
using System.docxusing System.docx
using System.docx
KunalkishorSingh4
 
Whats new in_csharp4
Whats new in_csharp4Whats new in_csharp4
Whats new in_csharp4
Abed Bukhari
 
Mixing functional and object oriented approaches to programming in C#
Mixing functional and object oriented approaches to programming in C#Mixing functional and object oriented approaches to programming in C#
Mixing functional and object oriented approaches to programming in C#
Mark Needham
 
Lowering in C#: What really happens with your code?, from NDC Oslo 2019
Lowering in C#: What really happens with your code?, from NDC Oslo 2019Lowering in C#: What really happens with your code?, from NDC Oslo 2019
Lowering in C#: What really happens with your code?, from NDC Oslo 2019
David Wengier
 
NetPonto - The Future Of C# - NetConf Edition
NetPonto - The Future Of C# - NetConf EditionNetPonto - The Future Of C# - NetConf Edition
NetPonto - The Future Of C# - NetConf Edition
Paulo Morgado
 
15. Streams Files and Directories
15. Streams Files and Directories 15. Streams Files and Directories
15. Streams Files and Directories
Intro C# Book
 
Tuga IT 2018 Summer Edition - The Future of C#
Tuga IT 2018 Summer Edition - The Future of C#Tuga IT 2018 Summer Edition - The Future of C#
Tuga IT 2018 Summer Edition - The Future of C#
Paulo Morgado
 
Concurrent Collections Object In Dot Net 4
Concurrent Collections Object In Dot Net 4Concurrent Collections Object In Dot Net 4
Concurrent Collections Object In Dot Net 4
Neeraj Kaushik
 
F# in the enterprise
F# in the enterpriseF# in the enterprise
F# in the enterprise
7sharp9
 
csharp dot net codes for practical examination
csharp dot net codes for practical examinationcsharp dot net codes for practical examination
csharp dot net codes for practical examination
SanikaPatil68377
 
Multi core programming 2
Multi core programming 2Multi core programming 2
Multi core programming 2
Robin Aggarwal
 
Oops pramming with examples
Oops pramming with examplesOops pramming with examples
Oops pramming with examples
Syed Khaleel
 
C# Starter L04-Collections
C# Starter L04-CollectionsC# Starter L04-Collections
C# Starter L04-Collections
Mohammad Shaker
 
How to capture a variable in C# and not to shoot yourself in the foot
How to capture a variable in C# and not to shoot yourself in the footHow to capture a variable in C# and not to shoot yourself in the foot
How to capture a variable in C# and not to shoot yourself in the foot
Sofia Fateeva
 
How to capture a variable in C# and not to shoot yourself in the foot
How to capture a variable in C# and not to shoot yourself in the footHow to capture a variable in C# and not to shoot yourself in the foot
How to capture a variable in C# and not to shoot yourself in the foot
PVS-Studio
 
Whats new in_csharp4
Whats new in_csharp4Whats new in_csharp4
Whats new in_csharp4
Abed Bukhari
 
Mixing functional and object oriented approaches to programming in C#
Mixing functional and object oriented approaches to programming in C#Mixing functional and object oriented approaches to programming in C#
Mixing functional and object oriented approaches to programming in C#
Mark Needham
 
Ad

More from Dhaval Dalal (20)

Sri-Aurobindos-Integral-Education-Principles.pdf
Sri-Aurobindos-Integral-Education-Principles.pdfSri-Aurobindos-Integral-Education-Principles.pdf
Sri-Aurobindos-Integral-Education-Principles.pdf
Dhaval Dalal
 
Test Pyramid in Microservices Context
Test Pyramid in Microservices ContextTest Pyramid in Microservices Context
Test Pyramid in Microservices Context
Dhaval Dalal
 
Code Retreat
Code RetreatCode Retreat
Code Retreat
Dhaval Dalal
 
Json Viewer Stories
Json Viewer StoriesJson Viewer Stories
Json Viewer Stories
Dhaval Dalal
 
Value Objects
Value ObjectsValue Objects
Value Objects
Dhaval Dalal
 
Mars rover-extension
Mars rover-extensionMars rover-extension
Mars rover-extension
Dhaval Dalal
 
How Is Homeopathy Near To Yoga?
How Is Homeopathy Near To Yoga?How Is Homeopathy Near To Yoga?
How Is Homeopathy Near To Yoga?
Dhaval Dalal
 
Approaching ATDD/BDD
Approaching ATDD/BDDApproaching ATDD/BDD
Approaching ATDD/BDD
Dhaval Dalal
 
Paradigms Code jugalbandi
Paradigms Code jugalbandiParadigms Code jugalbandi
Paradigms Code jugalbandi
Dhaval Dalal
 
Data Reconciliation
Data ReconciliationData Reconciliation
Data Reconciliation
Dhaval Dalal
 
CodeRetreat
CodeRetreatCodeRetreat
CodeRetreat
Dhaval Dalal
 
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr20154-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015
Dhaval Dalal
 
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar20153-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
Dhaval Dalal
 
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015
Dhaval Dalal
 
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-Issue
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-IssueCodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-Issue
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-Issue
Dhaval Dalal
 
The tao-of-transformation-workshop
The tao-of-transformation-workshopThe tao-of-transformation-workshop
The tao-of-transformation-workshop
Dhaval Dalal
 
Grooming with Groovy
Grooming with GroovyGrooming with Groovy
Grooming with Groovy
Dhaval Dalal
 
Language portfolio
Language portfolioLanguage portfolio
Language portfolio
Dhaval Dalal
 
Code jugalbandi
Code jugalbandiCode jugalbandi
Code jugalbandi
Dhaval Dalal
 
A case-for-graph-db
A case-for-graph-dbA case-for-graph-db
A case-for-graph-db
Dhaval Dalal
 
Sri-Aurobindos-Integral-Education-Principles.pdf
Sri-Aurobindos-Integral-Education-Principles.pdfSri-Aurobindos-Integral-Education-Principles.pdf
Sri-Aurobindos-Integral-Education-Principles.pdf
Dhaval Dalal
 
Test Pyramid in Microservices Context
Test Pyramid in Microservices ContextTest Pyramid in Microservices Context
Test Pyramid in Microservices Context
Dhaval Dalal
 
Json Viewer Stories
Json Viewer StoriesJson Viewer Stories
Json Viewer Stories
Dhaval Dalal
 
Mars rover-extension
Mars rover-extensionMars rover-extension
Mars rover-extension
Dhaval Dalal
 
How Is Homeopathy Near To Yoga?
How Is Homeopathy Near To Yoga?How Is Homeopathy Near To Yoga?
How Is Homeopathy Near To Yoga?
Dhaval Dalal
 
Approaching ATDD/BDD
Approaching ATDD/BDDApproaching ATDD/BDD
Approaching ATDD/BDD
Dhaval Dalal
 
Paradigms Code jugalbandi
Paradigms Code jugalbandiParadigms Code jugalbandi
Paradigms Code jugalbandi
Dhaval Dalal
 
Data Reconciliation
Data ReconciliationData Reconciliation
Data Reconciliation
Dhaval Dalal
 
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr20154-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015
4-Code-Jugalbandi-destructuring-patternmatching-healthycode#apr2015
Dhaval Dalal
 
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar20153-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
3-CodeJugalbandi-currying-pfa-healthycodemagazine#mar2015
Dhaval Dalal
 
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015
CodeJugalbandi-Sequencing-HealthyCode-Magazine-Feb-2015
Dhaval Dalal
 
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-Issue
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-IssueCodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-Issue
CodeJugalbandi-Expression-Problem-HealthyCode-Magazine#Jan-2015-Issue
Dhaval Dalal
 
The tao-of-transformation-workshop
The tao-of-transformation-workshopThe tao-of-transformation-workshop
The tao-of-transformation-workshop
Dhaval Dalal
 
Grooming with Groovy
Grooming with GroovyGrooming with Groovy
Grooming with Groovy
Dhaval Dalal
 
Language portfolio
Language portfolioLanguage portfolio
Language portfolio
Dhaval Dalal
 
A case-for-graph-db
A case-for-graph-dbA case-for-graph-db
A case-for-graph-db
Dhaval Dalal
 
Ad

Recently uploaded (20)

Data Virtualization: Bringing the Power of FME to Any Application
Data Virtualization: Bringing the Power of FME to Any ApplicationData Virtualization: Bringing the Power of FME to Any Application
Data Virtualization: Bringing the Power of FME to Any Application
Safe Software
 
IntroSlides-May-BuildWithAi-EarthEngine.pdf
IntroSlides-May-BuildWithAi-EarthEngine.pdfIntroSlides-May-BuildWithAi-EarthEngine.pdf
IntroSlides-May-BuildWithAi-EarthEngine.pdf
Luiz Carneiro
 
Oracle Cloud Infrastructure Generative AI Professional
Oracle Cloud Infrastructure Generative AI ProfessionalOracle Cloud Infrastructure Generative AI Professional
Oracle Cloud Infrastructure Generative AI Professional
VICTOR MAESTRE RAMIREZ
 
AI Agents in Logistics and Supply Chain Applications Benefits and Implementation
AI Agents in Logistics and Supply Chain Applications Benefits and ImplementationAI Agents in Logistics and Supply Chain Applications Benefits and Implementation
AI Agents in Logistics and Supply Chain Applications Benefits and Implementation
Christine Shepherd
 
Azure vs AWS Which Cloud Platform Is Best for Your Business in 2025
Azure vs AWS  Which Cloud Platform Is Best for Your Business in 2025Azure vs AWS  Which Cloud Platform Is Best for Your Business in 2025
Azure vs AWS Which Cloud Platform Is Best for Your Business in 2025
Infrassist Technologies Pvt. Ltd.
 
AI Creative Generates You Passive Income Like Never Before
AI Creative Generates You Passive Income Like Never BeforeAI Creative Generates You Passive Income Like Never Before
AI Creative Generates You Passive Income Like Never Before
SivaRajan47
 
Introduction to Typescript - GDG On Campus EUE
Introduction to Typescript - GDG On Campus EUEIntroduction to Typescript - GDG On Campus EUE
Introduction to Typescript - GDG On Campus EUE
Google Developer Group On Campus European Universities in Egypt
 
Extend-Microsoft365-with-Copilot-agents.pptx
Extend-Microsoft365-with-Copilot-agents.pptxExtend-Microsoft365-with-Copilot-agents.pptx
Extend-Microsoft365-with-Copilot-agents.pptx
hoang971
 
MCP vs A2A vs ACP: Choosing the Right Protocol | Bluebash
MCP vs A2A vs ACP: Choosing the Right Protocol | BluebashMCP vs A2A vs ACP: Choosing the Right Protocol | Bluebash
MCP vs A2A vs ACP: Choosing the Right Protocol | Bluebash
Bluebash
 
Improving Developer Productivity With DORA, SPACE, and DevEx
Improving Developer Productivity With DORA, SPACE, and DevExImproving Developer Productivity With DORA, SPACE, and DevEx
Improving Developer Productivity With DORA, SPACE, and DevEx
Justin Reock
 
The case for on-premises AI
The case for on-premises AIThe case for on-premises AI
The case for on-premises AI
Principled Technologies
 
LSNIF: Locally-Subdivided Neural Intersection Function
LSNIF: Locally-Subdivided Neural Intersection FunctionLSNIF: Locally-Subdivided Neural Intersection Function
LSNIF: Locally-Subdivided Neural Intersection Function
Takahiro Harada
 
If You Use Databricks, You Definitely Need FME
If You Use Databricks, You Definitely Need FMEIf You Use Databricks, You Definitely Need FME
If You Use Databricks, You Definitely Need FME
Safe Software
 
Evaluation Challenges in Using Generative AI for Science & Technical Content
Evaluation Challenges in Using Generative AI for Science & Technical ContentEvaluation Challenges in Using Generative AI for Science & Technical Content
Evaluation Challenges in Using Generative AI for Science & Technical Content
Paul Groth
 
Trends Report: Artificial Intelligence (AI)
Trends Report: Artificial Intelligence (AI)Trends Report: Artificial Intelligence (AI)
Trends Report: Artificial Intelligence (AI)
Brian Ahier
 
“State-space Models vs. Transformers for Ultra-low-power Edge AI,” a Presenta...
“State-space Models vs. Transformers for Ultra-low-power Edge AI,” a Presenta...“State-space Models vs. Transformers for Ultra-low-power Edge AI,” a Presenta...
“State-space Models vs. Transformers for Ultra-low-power Edge AI,” a Presenta...
Edge AI and Vision Alliance
 
Establish Visibility and Manage Risk in the Supply Chain with Anchore SBOM
Establish Visibility and Manage Risk in the Supply Chain with Anchore SBOMEstablish Visibility and Manage Risk in the Supply Chain with Anchore SBOM
Establish Visibility and Manage Risk in the Supply Chain with Anchore SBOM
Anchore
 
Create Your First AI Agent with UiPath Agent Builder
Create Your First AI Agent with UiPath Agent BuilderCreate Your First AI Agent with UiPath Agent Builder
Create Your First AI Agent with UiPath Agent Builder
DianaGray10
 
Boosting MySQL with Vector Search -THE VECTOR SEARCH CONFERENCE 2025 .pdf
Boosting MySQL with Vector Search -THE VECTOR SEARCH CONFERENCE 2025 .pdfBoosting MySQL with Vector Search -THE VECTOR SEARCH CONFERENCE 2025 .pdf
Boosting MySQL with Vector Search -THE VECTOR SEARCH CONFERENCE 2025 .pdf
Alkin Tezuysal
 
Developing Schemas with FME and Excel - Peak of Data & AI 2025
Developing Schemas with FME and Excel - Peak of Data & AI 2025Developing Schemas with FME and Excel - Peak of Data & AI 2025
Developing Schemas with FME and Excel - Peak of Data & AI 2025
Safe Software
 
Data Virtualization: Bringing the Power of FME to Any Application
Data Virtualization: Bringing the Power of FME to Any ApplicationData Virtualization: Bringing the Power of FME to Any Application
Data Virtualization: Bringing the Power of FME to Any Application
Safe Software
 
IntroSlides-May-BuildWithAi-EarthEngine.pdf
IntroSlides-May-BuildWithAi-EarthEngine.pdfIntroSlides-May-BuildWithAi-EarthEngine.pdf
IntroSlides-May-BuildWithAi-EarthEngine.pdf
Luiz Carneiro
 
Oracle Cloud Infrastructure Generative AI Professional
Oracle Cloud Infrastructure Generative AI ProfessionalOracle Cloud Infrastructure Generative AI Professional
Oracle Cloud Infrastructure Generative AI Professional
VICTOR MAESTRE RAMIREZ
 
AI Agents in Logistics and Supply Chain Applications Benefits and Implementation
AI Agents in Logistics and Supply Chain Applications Benefits and ImplementationAI Agents in Logistics and Supply Chain Applications Benefits and Implementation
AI Agents in Logistics and Supply Chain Applications Benefits and Implementation
Christine Shepherd
 
Azure vs AWS Which Cloud Platform Is Best for Your Business in 2025
Azure vs AWS  Which Cloud Platform Is Best for Your Business in 2025Azure vs AWS  Which Cloud Platform Is Best for Your Business in 2025
Azure vs AWS Which Cloud Platform Is Best for Your Business in 2025
Infrassist Technologies Pvt. Ltd.
 
AI Creative Generates You Passive Income Like Never Before
AI Creative Generates You Passive Income Like Never BeforeAI Creative Generates You Passive Income Like Never Before
AI Creative Generates You Passive Income Like Never Before
SivaRajan47
 
Extend-Microsoft365-with-Copilot-agents.pptx
Extend-Microsoft365-with-Copilot-agents.pptxExtend-Microsoft365-with-Copilot-agents.pptx
Extend-Microsoft365-with-Copilot-agents.pptx
hoang971
 
MCP vs A2A vs ACP: Choosing the Right Protocol | Bluebash
MCP vs A2A vs ACP: Choosing the Right Protocol | BluebashMCP vs A2A vs ACP: Choosing the Right Protocol | Bluebash
MCP vs A2A vs ACP: Choosing the Right Protocol | Bluebash
Bluebash
 
Improving Developer Productivity With DORA, SPACE, and DevEx
Improving Developer Productivity With DORA, SPACE, and DevExImproving Developer Productivity With DORA, SPACE, and DevEx
Improving Developer Productivity With DORA, SPACE, and DevEx
Justin Reock
 
LSNIF: Locally-Subdivided Neural Intersection Function
LSNIF: Locally-Subdivided Neural Intersection FunctionLSNIF: Locally-Subdivided Neural Intersection Function
LSNIF: Locally-Subdivided Neural Intersection Function
Takahiro Harada
 
If You Use Databricks, You Definitely Need FME
If You Use Databricks, You Definitely Need FMEIf You Use Databricks, You Definitely Need FME
If You Use Databricks, You Definitely Need FME
Safe Software
 
Evaluation Challenges in Using Generative AI for Science & Technical Content
Evaluation Challenges in Using Generative AI for Science & Technical ContentEvaluation Challenges in Using Generative AI for Science & Technical Content
Evaluation Challenges in Using Generative AI for Science & Technical Content
Paul Groth
 
Trends Report: Artificial Intelligence (AI)
Trends Report: Artificial Intelligence (AI)Trends Report: Artificial Intelligence (AI)
Trends Report: Artificial Intelligence (AI)
Brian Ahier
 
“State-space Models vs. Transformers for Ultra-low-power Edge AI,” a Presenta...
“State-space Models vs. Transformers for Ultra-low-power Edge AI,” a Presenta...“State-space Models vs. Transformers for Ultra-low-power Edge AI,” a Presenta...
“State-space Models vs. Transformers for Ultra-low-power Edge AI,” a Presenta...
Edge AI and Vision Alliance
 
Establish Visibility and Manage Risk in the Supply Chain with Anchore SBOM
Establish Visibility and Manage Risk in the Supply Chain with Anchore SBOMEstablish Visibility and Manage Risk in the Supply Chain with Anchore SBOM
Establish Visibility and Manage Risk in the Supply Chain with Anchore SBOM
Anchore
 
Create Your First AI Agent with UiPath Agent Builder
Create Your First AI Agent with UiPath Agent BuilderCreate Your First AI Agent with UiPath Agent Builder
Create Your First AI Agent with UiPath Agent Builder
DianaGray10
 
Boosting MySQL with Vector Search -THE VECTOR SEARCH CONFERENCE 2025 .pdf
Boosting MySQL with Vector Search -THE VECTOR SEARCH CONFERENCE 2025 .pdfBoosting MySQL with Vector Search -THE VECTOR SEARCH CONFERENCE 2025 .pdf
Boosting MySQL with Vector Search -THE VECTOR SEARCH CONFERENCE 2025 .pdf
Alkin Tezuysal
 
Developing Schemas with FME and Excel - Peak of Data & AI 2025
Developing Schemas with FME and Excel - Peak of Data & AI 2025Developing Schemas with FME and Excel - Peak of Data & AI 2025
Developing Schemas with FME and Excel - Peak of Data & AI 2025
Safe Software
 

Creating Lazy stream in CSharp

  • 1. Hand-Toss a Stream (Lazy List) in C# Dhaval Dalal https://dhavaldalal.wordpress.com @softwareartisan
  • 2. Implementing Lazy List IEnumerable<int> Naturals(int @from) {
 for (var i = @from; true ; i++) {
 yield return i;
 }
 }
 Naturals(0) .Take(3) .ForEach(Console.WriteLine); // 0 1 2 Using generators This is the idiomatic approach. There is yet another one as well.
  • 4. Using Lambda Wrap the tail of the list in a closure. 1 ? Implementing Lazy List
  • 5. Using Lambda Wrap the tail of the list in a closure. When we need the result evaluate the tail by invoking the closure. Evaluate tail 1 ? 1 * 2 ? Implementing Lazy List
  • 6. Using Lambda Wrap the tail of the list in a closure. When we need the result evaluate the tail by invoking the closure. Additionally for performance - Cache or Memoize the closure output. Evaluate tail 1 ? 1 * 2 ? Implementing Lazy List
  • 7. Using Lambda Wrap the tail of the list in a closure. When we need the result evaluate the tail by invoking the closure. Additionally for performance - Cache or Memoize the closure output. Evaluate tail 1 ? 1 * 2 ? Implementing Lazy List Stream implementation shown in these slides is available on: https://github.com/CodeJugalbandi/FunctionalProgramming/blob/master/melodies/lazy_sequences/Stream.cs
  • 8. Immutable Stream with eager Head & lazy Tail sealed class Stream<T> {
 private readonly T head;
 private readonly Func<Stream<T>> tail;
 
 public Stream(T head, Func<Stream<T>> tail) {
 this.head = head;
 this.tail = tail;
 }
 public T Head {
 get => head;
 }
 public Stream<T> Tail {
 get => tail(); // Need Memoization (for Perf)
 }
 public override string ToString() => $"Stream<{typeof(T)}>({head}, ?)";
 }
  • 9. Immutable Stream with eager Head & lazy Tail sealed class Stream<T> {
 private readonly T head;
 private readonly Lazy<Stream<T>> tail;
 
 public Stream(T head, Lazy<Stream<T>> tail) {
 this.head = head;
 this.tail = tail;
 }
 public T Head {
 get => head;
 }
 public Stream<T> Tail {
 get => tail.Value; // Cached after first eval
 }
 public override string ToString() => $"Stream<{typeof(T)}>({head}, ?)";
 }
  • 10. Immutable Stream with eager Head & lazy Tail var empty = new Stream<int>(0, null);
 Console.WriteLine(empty); // Stream<System.Int32>(0, ?)
 Console.WriteLine(empty.Head); // 0
 Console.WriteLine(empty.Tail);
 
 var singleton = new Stream<int>(1, new Lazy<Stream<int>>(() => empty));
 Console.WriteLine(singleton); // Stream<System.Int32>(1, ?)
 Console.WriteLine(singleton.Head); // 1
 Console.WriteLine(singleton.Tail); // Stream<System.Int32>(0, ?)
 
 var couple = new Stream<int>(2, new Lazy<Stream<int>>(() => singleton));
 Console.WriteLine(couple); // Stream<System.Int32>(2, ?)
 Console.WriteLine(couple.Head); // 2
 Console.WriteLine(couple.Tail); // Stream<System.Int32>(1, ?)
 Console.WriteLine(couple.Tail.Tail); // Stream<System.Int32>(0, ?)
 Console.WriteLine(couple.Tail.Tail.Tail); As Streams are immutable we can structurally share the earlier stream. Boom! Boom!
  • 11. Introduce Empty Stream sealed class Stream<T> {
 public static readonly Stream<T> Empty = new Stream<T>(default(T), null);
 private readonly T head;
 private readonly Lazy<Stream<T>> tail;
 public Stream(T head, Lazy<Stream<T>> tail) { … }
 public T Head { … }
 public Stream<T> Tail { … }
 public bool IsEmpty {
 get => tail == null;
 }
 public override string ToString() {
 if (IsEmpty) 
 return "Empty";
 
 return $"Stream<{typeof(T)}>({head}, ?)";
 }
 }
  • 12. Introduce Empty Stream var empty = Stream<int>.Empty;
 Console.WriteLine(empty); // Empty
 Console.WriteLine(empty.IsEmpty); // True
 
 var singleton = new Stream<int>(1, new Lazy<Stream<int>>(() => empty));
 Console.WriteLine(singleton); // Stream(1, ?)
 Console.WriteLine(singleton.IsEmpty); // False
 
 var couple = new Stream<int>(2, new Lazy<Stream<int>>(() => singleton));
 Console.WriteLine(couple); // Stream(2, ?)
 Console.WriteLine(couple.IsEmpty); // False
  • 13. Doing Side-effects sealed class Stream<T> { … …
 public void ForEach(Action<T> action) {
 if (IsEmpty)
 return; 
 action(Head);
 Tail.ForEach(action);
 }
 } var empty = Stream<int>.Empty;
 empty.ForEach(Console.WriteLine); // Prints Nothing
 var stream = new Stream<int>(2, new Lazy<Stream<int>>(new Stream<int>(1, new Lazy<Stream<int>>(() => empty))));
 stream.ForEach(Console.WriteLine); // 2 1
  • 14. Consing to Stream sealed class Stream<T> {
 … …
 // Cons using +
 public static Stream<T> operator + (Stream<T> s, T element) => 
 new Stream<T>(element, new Lazy<Stream<T>>(() => s));
 } var stream = Stream<int>.Empty + 1 + 2;
 Console.WriteLine(stream); // Stream(2, ?)
 Console.WriteLine(stream.Head); // 2
 Console.WriteLine(stream.Tail); // Stream(1, ?) 
 stream.ForEach(Console.WriteLine); // 2 1 Prepend (Cons)
  • 15. Append to Stream sealed class Stream<T> { …
 // Append using +
 public static Stream<T> operator + (T element, Stream<T> s) => 
 new Stream<T>(element, new Lazy<Stream<T>>(() => s.IsEmpty ? Stream<T>.Empty : s));
 } var stream = 1 + Stream<int>.Empty;
 stream.ForEach(Console.WriteLine); // 1
 
 var stream = 1 + (2 + (3 + (4 + Stream<int>.Empty)));
 stream.ForEach(Console.WriteLine); // 1 2 3 4
  • 16. sealed class Stream<T> { … public static Stream<R> Of<R>(params R[] rs) {
 var stream = Stream<R>.Empty;
 var indices = rs.Length - 1;
 for (var i = indices; i >= 0; i--) {
 stream = stream + rs[i];
 }
 return stream;
 }
 } Stream<int>.Of<int>() .ForEach(Console.WriteLine); // Prints Nothing Stream<int>.Of(1, 2, 3, 4) .ForEach(Console.WriteLine); // 1 2 3 4 Construct a Stream from few elements
  • 17. Concat another Stream sealed class Stream<T> {
 …
 public static Stream<T> operator + (Stream<T> @this, Stream<T> other) { if (@this.IsEmpty)
 return other;
 
 return new Stream<T>(@this.Head, new Lazy<Stream<T>>(() => @this.Tail + other));
 } } var concat1 = Stream<char>.Empty + Stream<char>.Of('a', 'b');
 concat1.ForEach(Console.Write); // ab
 
 var concat2 = Stream<char>.Of('a', 'b') + Stream<char>.Empty;
 concat2.ForEach(Console.Write); // ab
 
 var concat3 = Stream<char>.Of('a', 'b') + Stream<char>.Of('c', 'd', 'e');
 concat3.ForEach(Console.Write); // abcde
  • 18. sealed class Stream<T> {
 … public Stream<T> Take(int howMany) {
 if (IsEmpty || howMany <= 0)
 return Stream<T>.Empty;
 
 return new Stream<T>(Head, new Lazy<Stream<T>>(() => Tail.Take(howMany - 1)));
 }
 } Stream<int>.Empty .Take(2).ForEach(Console.WriteLine); // Prints Nothing
 Stream<int>.Of(1, 2, 3, 4) .Take(2).ForEach(Console.WriteLine); // 1 2
 Stream<int>.Of(1, 2, 3, 4) .Take(12).ForEach(Console.WriteLine); // 1 2 3 4
 Stream<int>.Of(1, 2, 3, 4) .Take(0).ForEach(Console.WriteLine); // Prints Nothing Take few elements
  • 19. sealed class Stream<T> {
 … public Stream<T> Drop(int howMany) {
 if (IsEmpty || howMany <= 0)
 return this;
 
 return Tail.Drop(howMany - 1);
 }
 } Stream<int>.Empty .Drop(2).ForEach(Console.WriteLine); // Prints Nothing
 Stream<int>.Of(1, 2, 3, 4) .Drop(2).ForEach(Console.WriteLine); // 3 4
 Stream<int>.Of(1, 2, 3, 4) .Drop(20).ForEach(Console.WriteLine); // Prints Nothing
 Stream<int>.Of(1, 2, 3, 4) .Drop(0).ForEach(Console.WriteLine); // 1 2 3 4 Drop few elements
  • 20. sealed class Stream<T> {
 … … public static Stream<R> Generate<R>(Func<R> fn) => 
 new Stream<R>(fn(), new Lazy<Stream<R>>(() => Generate(fn))); } var random = new Random();
 Stream<int>.Generate(() => random.Next(100, 150)) .Take(4) .ForEach(Console.WriteLine); // Prints 4 random numbers bet [100, 150) Construct a Stream using lambda - 1
  • 21. sealed class Stream<T> {
 … … public static Stream<R> Iterate<R>(R initial, Func<R, R> fn) => 
 new Stream<R>(initial, new Lazy<Stream<R>>(() => Iterate(fn(initial), fn)));
 } Stream<int>.Iterate(9, x => x + 2) .Take(4) .ForEach(Console.WriteLine); // 9 11 13 15 Construct a Stream using lambda - 2
  • 22. sealed class Stream<T> {
 … … public void Deconstruct(out T first, out Stream<T> rest) {
 if (IsEmpty) 
 throw new ArgumentException("Collection is Empty!");
 
 first = Head;
 rest = Drop(1);
 }
 } var (head, rest) = Stream<int>.Of(1, 2, 3, 4);
 Console.WriteLine("Head = " + head); // 1
 Console.WriteLine("Rest = " + rest); // Stream(2, ?) Deconstruct a Stream
  • 23. sealed class Stream<T> {
 … public void Deconstruct(out T first, out Stream<T> rest) {
 if (IsEmpty) 
 throw new ArgumentException("Collection is Empty!");
 
 first = Head;
 rest = Drop(1);
 }
 public void Deconstruct(out T first, out T second, out Stream<T> rest) => (first, (second, rest)) = this; 
 } var (head, second, rest) = Stream<int>.Of(1, 2, 3, 4); Console.WriteLine("Head = " + head); // 1 Console.WriteLine("Second = " + second); // 2 Console.WriteLine("Rest = " + rest); // Stream(2, ?) Deconstruct a Stream
  • 24. sealed class Stream<T> {
 … public void Deconstruct(out T first, out T second, out Stream<T> rest) =>
 (first, (second, rest)) = this;
 
 public void Deconstruct(out T first, out T second, out T third, out Stream<T> rest) =>
 (first, second, (third, rest)) = this;
 } var (head, second, third, rest) = Stream<int>.Of(1, 2, 3, 4);
 Console.WriteLine("Head = " + head); // 1
 Console.WriteLine("Second = " + second); // 2
 Console.WriteLine("Third = " + third); // 3
 Console.WriteLine("Rest = " + rest); // Stream(4, ?) Deconstruct a Stream
  • 25. Transform each element sealed class Stream<T> {
 … …
 public Stream<R> Select<R>(Func<T, R> fn) {
 if (IsEmpty)
 return Stream<R>.Empty;
 
 return new Stream<R>(fn(Head), new Lazy<Stream<R>>(() => Tail.Select(fn)));
 }
 } var empty = Stream<int>.Empty; Console.WriteLine(empty.Select(x => x * x)); // Prints Nothing var stream = Stream<int>.Of(1, 2);
 Console.WriteLine(stream.Select(x => x * x)); // 1 4
  • 26. Filtering the Stream sealed class Stream<T> {
 …
 public Stream<T> Where(Predicate<T> pred) {
 if (IsEmpty)
 return Stream<T>.Empty;
 
 if (pred(Head)) 
 return new Stream<T>(Head, new Lazy<Stream<T>>(() => Tail.Where(pred)));
 
 return Tail.Where(pred);
 }
 } var empty = Stream<int>.Empty; Console.WriteLine(empty.Where(x => x < 2)); // Prints Nothing var stream = Stream<int>.Of(1, 2);
 Console.WriteLine(stream.Where(x => x < 2)); // 1
  • 27. Flatmap the Stream sealed class Stream<T> { …
 public Stream<T> SelectMany(Func<T, Stream<R>> fn) {
 if (IsEmpty)
 return Stream<R>.Empty;
 
 return fn(Head) + Tail.SelectMany(fn);
 }
 } Stream<char>.Of('a', 'b')
 .SelectMany(c => Stream<int>.Of(1, 2).Select(n => (c, n)))
 .ForEach(t => Console.Write(t)); // (a, 1)(a, 2)(b, 1)(b, 2)
 
 Stream<int>.Empty.SelectMany(c => Stream<int>.Of(1, 2).Select(n => (c, n)))
 .ForEach(t => Console.Write(t)); // Prints Nothing
  • 28. Reverse sealed class Stream<T> {
 … …
 public Stream<T> Reverse() {
 Stream<T> Reverse0(Stream<T> acc, Stream<T> source) {
 if (source.IsEmpty)
 return acc;
 
 return Reverse0(acc + source.Head, source.Tail);
 }
 return Reverse0(Stream<T>.Empty, this);
 }
 } Stream<char>.Of('a', 'b', ‘c') .Reverse().ForEach(Console.Write); // cba 
 Stream<int>.Empty .Reverse().ForEach(Console.WriteLine); // Prints Nothing
  • 29. Take while predicate holds sealed class Stream<T> {
 …
 public Stream<T> TakeWhile(Predicate<T> pred) {
 if (IsEmpty)
 return Stream<T>.Empty;
 
 if (pred(Head))
 return Head + Tail.TakeWhile(pred);
 
 return Stream<T>.Empty;
 }
 } Stream<char>.Of('a', 'a', 'b', 'c').TakeWhile(c => c == 'a')
 .ForEach(Console.Write); // aa
 
 Stream<char>.Of('a', 'a', 'b', 'c').TakeWhile(c => c == 'b')
 .ForEach(Console.Write); // Prints Nothing
  • 30. sealed class Stream<T> {
 …
 public Stream<T> DropWhile(Predicate<T> pred) {
 if (IsEmpty)
 return Stream<T>.Empty;
 
 if (pred(Head))
 return Tail.DropWhile(pred);
 
 return this;
 }
 } Stream<char>.Of('a', 'a', 'b', 'c').DropWhile(c => c == 'a')
 .ForEach(Console.Write); // bc
 
 Stream<char>.Of('a', 'a', 'b', 'c').DropWhile(c => c == 'b')
 .ForEach(Console.Write); // aabc Drop while predicate holds
  • 31. sealed class Stream<T> {
 …
 public U Aggregate<U>(U identity, Func<U, T, U> func) {
 if (IsEmpty)
 return identity;
 
 return Tail.Aggregate(func(identity, Head), func);
 }
 } var sum1 = Stream<int>.Of(1, 2, 3, 4) .Aggregate(0, (acc, elem) => acc + elem);
 Console.WriteLine($"sum = {sum1}"); // 10
 var sum2 = Stream<int>.Of<int>() .Aggregate(0, (acc, elem) => acc + elem); 
 Console.WriteLine($"sum = {sum2}"); // 0 Aggregate or Reduce
  • 32. sealed class Stream<T> {
 …
 public bool All(Predicate<T> pred) {
 bool All0(bool accumulator, Stream<T> stream) {
 if (stream.IsEmpty || accumulator == false)
 return accumulator;
 
 return All0(accumulator && pred(stream.Head), stream.Tail);
 }
 return All0(true, this);
 }
 } Console.WriteLine(Stream<int>.Of<int>().All(x => x % 2 == 0)); // True
 Console.WriteLine(Stream<int>.Of<int>(2, 4).All(x => x % 2 == 0)); // True
 Console.WriteLine(Stream<int>.Of<int>(1, 2, 4).All(x => x % 2 == 0)); // False All Don’t evaluate the entire Stream, short-circuit if we already determined negation.
  • 33. sealed class Stream<T> {
 …
 public bool Any(Predicate<T> pred) {
 bool Any0(bool accumulator, Stream<T> stream) {
 if (stream.IsEmpty || accumulator == true)
 return accumulator;
 
 return Any0(accumulator || pred(stream.Head), stream.Tail);
 }
 return Any0(false, this);
 }
 } Console.WriteLine(Stream<int>.Of<int>().Any(x => x % 2 == 0)); // False
 Console.WriteLine(Stream<int>.Of<int>(2, 4).Any(x => x % 2 == 0)); // True
 Console.WriteLine(Stream<int>.Of<int>(1, 2, 4).Any(x => x % 2 == 0)); // True
 Console.WriteLine(Stream<int>.Of<int>(1, 3).Any(x => x % 2 == 0)); // False Any Don’t evaluate the entire Stream, short-circuit if we already determined affirmation.
  • 34. sealed class Stream<T> {
 …
 public Stream<T> Scan(U identity, Func<U, T, U> func) {
 if (IsEmpty)
 return Stream<T>.Empty;
 
 U newHead = func(identity, Head);
 return newHead + Tail.Scan(newHead, func);
 }
 } // Prints running sum
 Stream<int>.Of(1, 2, 3, 4) .Scan(0, (acc, elem) => acc + elem) .ForEach(Console.WriteLine); // 1 3 6 10
 Stream<int>.Of<int>() .Scan(0, (acc, elem) => acc + elem) .ForEach(Console.WriteLine); // Prints Nothing Scan
  • 35. Zip two Streams sealed class Stream<T> {
 …
 public Stream<(T,U)> Zip<U>(Stream<U> that) {
 if (this.IsEmpty || that.IsEmpty)
 return Stream<(T,U)>.Empty;
 
 return (this.Head, that.Head) + this.Tail.Zip(that.Tail);
 }
 } Stream<char>.Of('a', 'b').Zip(Stream<int>.Of(1, 2))
 .ForEach(t => Console.Write(t)); // (a, 1)(b, 2)
 
 Stream<char>.Of('a', 'b').Zip(Stream<int>.Empty)
 .ForEach(t => Console.Write(t)); // Prints Nothing
 
 Stream<int>.Empty.Zip(Stream<char>.Of('a', 'b'))
 .ForEach(t => Console.Write(t)); // Prints Nothing
  • 36. Zip with function sealed class Stream<T> {
 …
 public Stream<R> ZipWith<U, R>(Stream<U> that, Func<T, U, R> fn) {
 if (this.IsEmpty || that.IsEmpty)
 return Stream<R>.Empty;
 
 return fn(this.Head, that.Head) + this.Tail.ZipWith(that.Tail, fn);
 }
 } var numbers = Stream<int>.Of(1, 2, 3);
 numbers.ZipWith(numbers, (n1, n2) => n1 * n2)
 .ForEach(Console.WriteLine); // 1 4 9
 
 numbers.ZipWith(Stream<int>.Empty, (n1, n2) => n1 * n2)
 .ForEach(Console.WriteLine); // Prints Nothing
 
 Stream<int>.Empty.ZipWith(numbers, (n1, n2) => n1 * n2)
 .ForEach(Console.WriteLine); // Prints Nothing
  • 37. Splitsealed class Stream<T> {
 …
 public (Stream<T>, Stream<T>) Split(Predicate<T> pred) {
 (Stream<T>, Stream<T>) Split0(Stream<T> yesAcc, Stream<T> noAcc, Stream<T> source) {
 if (source.IsEmpty) 
 return (yesAcc.Reverse(), noAcc.Reverse());
 
 var elem = source.Head;
 if (pred(elem))
 return Split0(yesAcc + elem, noAcc, source.Tail);
 else
 return Split0(yesAcc, noAcc + elem, source.Tail);
 } 
 return Split0(Stream<T>.Empty, Stream<T>.Empty, this);
 }
 } var (evens, odds) = Stream<int>.Iterate(0, x => x + 1).Take(10) .Split(x => x % 2 == 0);
 evens.ForEach(Console.Write); // 02468
 odds.ForEach(Console.Write); // 13579
  • 38. To List sealed class Stream<T> {
 … public List<T> ToList() {
 var result = new List<T>();
 ForEach(result.Add);
 return result;
 }
 } var list = Stream<int>.Iterate(1, x => x + 1) .Take(4) .ToList();
 foreach (var item in list) {
 Console.WriteLine(item);
 }
  • 39. Find first 6 primes using the Sieve of Eratosthenes Hint: Use Stream created earlier http://world.mathigon.org/Prime_Numbers
  • 40. Sieve Stream<int> From(int start) => Stream<int>.Iterate(start, x => x + 1);
 Stream<int> Sieve(Stream<int> s) {
 var first = s.Head;
 var rest = s.Tail.Where(n => n % first != 0);
 return new Stream<int>(first, new Lazy<Stream<int>>(() => rest));
 }
 
 var primes = Sieve(From(2)).Take(6) primes.ToList() // [2, 3, 5, 7, 11, 13]
  • 41. First 10 Fibonacci Nos. Write a function fibonacci which consumes an integer and produces that many numbers in the fibonacci series. For Example: fibonacci(10) produces [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] Provide Solutions Using Generator Using IEnumerable Using Stream that we developed
  • 42. IEnumerable<int> Fibonacci(int howMany) { var (first, second) = (0, 1);
 for (var i = 0; i < howMany; i++) {
 yield return first;
 (first, second) = (second, first + second);
 }
 }
 
 Fibonacci(10).ToList();
 // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] First 10 Fibonacci Nos. Using Generator
  • 43. IEnumerable<int> Fibonacci(int howMany) { return IEnumerableExtensions.Iterate<(int, int)>((0, 1), tuple => {
 var (first, second) = tuple;
 var next = first + second;
 return (second, next);
 })
 .Select(tuple => {
 var (first, second) = tuple;
 return first;
 })
 .Take(howMany);
 } Fibonacci(10).ToList(); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] First 10 Fibonacci Nos. Using IEnumerable Definition as suggested by Christopher Grande
  • 44. First 10 Fibonacci Nos. Using Stream https://www.haskell.org/tutorial/functions.html var seed = From(0).Take(2);
 // Start with seed elements 0 and 1
 Fibonacci(seed)
 .Take(10)
 .ForEach(Console.WriteLine); // 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 Stream<int> Fibonacci(Stream<int> s) {
 var next = s.Zip(s.Tail).Select(tuple => {
 var (first, second) = tuple;
 return first + second;
 });
 return new Stream<int>(s.Head, new Lazy<Stream<int>>(() => Fibonacci(s + next.Head)));
 }
  • 45. Prime Counts Using Lazy Lists, write a program that counts number of primes up to a given number. At every power of 10, it should emit the count of primes obtained thus far. The table shows the output until 10 10 Implement this using: Using Stream we developed earlier. Using IEnumerable Hint: Write an extension method Scan on IEnumerable i/p count 10 4 10 2 25 10 3 168 10 4 1,229 10 5 9,592 10 6 78,498 10 7 6,64,579 10 8 57,61,455 10 9 5,08,47,534 10 10 45,50,52,511
  • 46. class Streams {
 public static Stream<int> Range(int start, int count) {
 if (count < 0)
 throw new ArgumentOutOfRangeException($"{count}");
 
 return Stream<int>.Iterate(start, x => x + 1).Take(count);
 } 
 }
 Streams.Range(1, 5).ForEach(Console.WriteLine); // 1 2 3 4 5 Prime Counts using IEnumerable First, write our own Range
  • 47. Prime Counts Using Stream Stream<(int, int)> PrimeCount(int howManyPowerOf10) {
 bool IsPrime(int x) => Streams.Range(2, x) .Where(n => n < x) .All(n => x % n != 0); 
 return Stream<int>.Iterate(2, x => x + 1)
 .TakeWhile(x => x <= Math.Pow(10, howManyPowerOf10))
 .Select(x => (x, IsPrime(x)))
 .Scan((0, 0), (acc, tuple) => {
 var (x, isPrime) = tuple;
 var (_, count) = acc;
 return isPrime ? (x, count + 1): (x, count);
 })
 .Where(tuple => {
 var (x, _) = tuple;
 return Streams.Range(1, howManyPowerOf10)
 .Any(n => Math.Pow(10, n) == x);
 });
 } PrimeCount(3).ForEach(t => Console.WriteLine(t)); (10, 4), (100, 25), (1000, 168)
  • 48. Prime Counts using IEnumerable First, write our own Scan static class IEnumerableExtensions { public static IEnumerable<U> Scan<T, U>(this IEnumerable<T> @this, U initial, Func<U, T, U> fn) {
 IEnumerable<U> ScannedEnumerable() {
 var acc = seed;
 foreach (var item in @this) {
 acc = fn(acc, item);
 yield return acc;
 } 
 if (@this == null)
 throw new ArgumentNullException("Require non-null list!");
 if (fn == null)
 throw new ArgumentNullException("Require non-null function!”);
 return ScannedEnumerable();
 } }
  • 49. Prime Counts using IEnumerable IEnumerable<(int, int)> PrimeCount(int howManyPowerOf10) {
 bool IsPrime(int x) => Enumerable.Range(2, x) .Where(n => n < x) .All(n => x % n != 0); 
 return IEnumerableExtensions.Iterate(2, x => x + 1)
 .TakeWhile(x => x <= Math.Pow(10, howManyPowerOf10))
 .Select(x => (x, IsPrime(x)))
 .Scan((0, 0), (acc, tuple) => {
 var (x, isPrime) = tuple;
 var (_, count) = acc;
 return isPrime ? (x, count + 1): (x, count);
 })
 .Where(tuple => {
 var (x, _) = tuple;
 return Enumerable.Range(1, howManyPowerOf10)
 .Any(n => Math.Pow(10, n) == x);
 });
 } PrimeCount(3).ForEach(t => Console.WriteLine(t)); (10, 4), (100, 25), (1000, 168)
  • 50. Drawbacks of this Stream Implementation As C# compiler does not support Tail- Recursion, all the APIs that are implemented recursively will cause a stack blow-up at some point for large values of stream. Even-though it uses caching of tail using Lazy<T>, this Stream is not performant like IEnumerable! This is because the recursive APIs don’t run in constant stack space.
  • 51. But still its a good mental exercise to create streams from first principles!