Created
August 24, 2017 21:22
-
-
Save samouss/1427a43d0e3ea4be207322724e658f37 to your computer and use it in GitHub Desktop.
Scala Stream
This file contains hidden or 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
class e1_bonus_stream extends HandsOnSuite { | |
sealed trait Stream[+A] { | |
def map[B](fonction:A => B):Stream[B] | |
def flatMap[B](fonction:A => Stream[B]):Stream[B] | |
def filter(fonction:A => Boolean):Stream[A] | |
final def union[B >: A](stream: => Stream[B]):Stream[B]= { | |
this match { | |
case EmptyStream => stream | |
case Cons(head, tail) => Cons(head, union(tail)) | |
} | |
} | |
def isEmpty:Boolean | |
def take(n: Int): Stream[A] = { | |
this match { | |
case EmptyStream => EmptyStream | |
case cons: Cons[A] => { | |
if (n <= 0) EmptyStream | |
else if (n == 1) Cons(cons.head, EmptyStream) | |
else Cons(cons.head, cons.tail.take(n - 1)) | |
} | |
} | |
} | |
def foreach(effetDeBord:A => Unit):Unit | |
} | |
object Stream { | |
// 'A*' signifie var args de A | |
def apply[A](values:A*):Stream[A] = { | |
if (values.isEmpty) { | |
EmptyStream | |
} else { | |
// ':_*' permet d'étendre une Stream en var args | |
Cons(values.head, Stream(values.tail:_*)) | |
} | |
} | |
def unapply[A](xs: Stream[A]): Option[(A, Stream[A])] = { | |
xs match { | |
case EmptyStream => None | |
case cons:Cons[A] => Some((cons.head, cons.tail)) | |
} | |
} | |
} | |
/** | |
* Cons veut dire Constructor, c'est lui qui permet de construire la Stream en ajoutant un élément | |
* à la queue | |
*/ | |
final class Cons[A](val head:A, tl: => Stream[A]) extends Stream[A] { | |
def isEmpty = false | |
// ce mécanisme permet de garantir la lazyness de la queue de la stream | |
// ainsi que la mémoization des valeurs accédées | |
lazy val tail:Stream[A] = tl | |
def map[B](fonction:A => B):Stream[B] = Cons(fonction(head), tail.map(fonction)) | |
/** | |
* l'implémentation de flatMap a besoin d'union | |
*/ | |
def flatMap[B](fonction:A => Stream[B]):Stream[B] = { | |
fonction(head).union(tail.flatMap(fonction)) | |
} | |
override def filter(fonction:A => Boolean):Stream[A] = { | |
if (fonction(head)) { | |
Cons(head, tail.filter(fonction)) | |
} else { | |
tail.filter(fonction) | |
} | |
} | |
override def equals(that: Any):Boolean = this == that | |
override def hashCode():Int = head.hashCode() | |
override def foreach(effetDeBord:A => Unit):Unit = { | |
effetDeBord(head) | |
tail.foreach(effetDeBord) | |
} | |
override def toString: String = "Cons(" + head + "," + tail.toString + ")" | |
} | |
object Cons { | |
def apply[A](head:A, tl: => Stream[A]) = new Cons(head,tl) | |
def unapply[A](cons:Cons[A]) = Stream.unapply(cons) | |
} | |
/** | |
* il y a qu'un seul EmptyStream, donc cela peut être un case object | |
*/ | |
case object EmptyStream extends Stream[Nothing] { | |
type A = Nothing | |
def map[B](fonction:A => B):Stream[B] = EmptyStream | |
def flatMap[B](fonction:A => Stream[B]):Stream[B] = EmptyStream | |
def filter(fonction:A => Boolean):Stream[A] = EmptyStream | |
def isEmpty: Boolean = true | |
def foreach(effetDeBord:A => Unit):Unit = {} | |
override def toString: String = "EmptyStream" | |
} | |
exercice("lazyness 2") { | |
val s:Stream[Int] = Stream(1,2,3).map{ | |
case 1 => 1 | |
case _ => { | |
throw new Exception("I should be lazy") | |
} | |
} | |
// Dont throw | |
println(s.flatMap(x => Stream(x)).take(1).toString) | |
// Throw | |
println(s.flatMap(x => s.map(y => x + y)).take(1).toString) | |
val s2 = for (i <- s; j <- s) yield(i + j) | |
// Throw | |
s2.take(1).foreach(println) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment