Created
July 7, 2020 07:59
-
-
Save Vilkina/452d9a67ba79e9c2a9653c8d87ae12c9 to your computer and use it in GitHub Desktop.
Example of implementing stream
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package exercises | |
import scala.annotation.tailrec | |
abstract class MyStream[+A] { | |
def isEmpty: Boolean | |
def head: A | |
def tail: MyStream[A] | |
def #::[B >: A](element: B): MyStream[B] | |
def ++[B >: A](anotherStream: MyStream[B]): MyStream[B] | |
def foreach(f: A => Unit): Unit | |
def map[B](f: A => B): MyStream[B] | |
def flatMap[B](f: A => MyStream[B]): MyStream[B] | |
def filter(predicate: A => Boolean): MyStream[A] | |
def take(n: Int): MyStream[A] | |
def takeAsList(n: Int): List[A] = take(n).toList() | |
@tailrec | |
final def toList[B >: A](acc: List[B] = Nil): List[B] = | |
if(isEmpty) acc | |
else tail.toList(head :: acc) | |
} | |
object EmptyStream extends MyStream[Nothing] { | |
def isEmpty: Boolean = true | |
def head: Nothing = throw new NoSuchElementException | |
def tail: MyStream[Nothing] = throw new NoSuchElementException | |
def #::[B >: Nothing](element: B): MyStream[B] = new Cons(element, EmptyStream) | |
def ++[B >: Nothing](anotherStream: MyStream[B]): MyStream[B] = anotherStream | |
def foreach(f: Nothing => Unit): Unit = () | |
def map[B](f: Nothing => B): MyStream[B] = this | |
def flatMap[B](f: Nothing => MyStream[B]): MyStream[B] = this | |
def filter(predicate: Nothing => Boolean): MyStream[Nothing] = this | |
def take(n: Int): MyStream[Nothing] = this | |
} | |
class Cons[+A](hd: A, tl: => MyStream[A]) extends MyStream[A] { | |
def isEmpty: Boolean = false | |
override val head: A = hd | |
override lazy val tail: MyStream[A] = tl | |
def #::[B >: A](element: B): MyStream[B] = new Cons(element, this) | |
def ++[B >: A](anotherStream: MyStream[B]): MyStream[B] = new Cons(head, tail ++ anotherStream) | |
def foreach(f: A => Unit): Unit = { | |
f(head) | |
tail.foreach(f) | |
} | |
def map[B](f: A => B): MyStream[B] = new Cons(f(head), tail.map(f)) | |
def flatMap[B](f: A => MyStream[B]): MyStream[B] = f(head) ++ tail.flatMap(f) | |
def filter(predicate: A => Boolean): MyStream[A] = | |
if (predicate(head)) new Cons(head, tail.filter(predicate)) | |
else tail.filter(predicate) | |
def take(n: Int): MyStream[A] = | |
if (n <= 0) EmptyStream | |
else if(n == 1) new Cons(head, EmptyStream) | |
else new Cons(head, tail.take(n-1)) | |
} | |
object MyStream { | |
def from[A](start: A)(generator: A => A): MyStream[A] = | |
new Cons(start, MyStream.from(generator(start))(generator)) | |
} | |
object StreamsPlayground extends App { | |
val naturals = MyStream.from(1)(_ + 1) | |
println(naturals.head) | |
println(naturals.tail.head) | |
println(naturals.tail.tail.head) | |
val startFromO = 0 #:: naturals | |
println(startFromO.head) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment