From 7e7ca849794f1404dc020b326867359bfcd43b75 Mon Sep 17 00:00:00 2001 From: Mike Curry Date: Sun, 3 Jan 2016 22:15:41 +0000 Subject: [PATCH] Adds Show[Stream] --- core/src/main/scala/cats/std/stream.scala | 6 +++++ .../test/scala/cats/tests/StreamTests.scala | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/core/src/main/scala/cats/std/stream.scala b/core/src/main/scala/cats/std/stream.scala index 988748b09d..3435e290fc 100644 --- a/core/src/main/scala/cats/std/stream.scala +++ b/core/src/main/scala/cats/std/stream.scala @@ -2,6 +2,7 @@ package cats package std import scala.collection.immutable.Stream.Empty +import cats.syntax.show._ trait StreamInstances { implicit val streamInstance: Traverse[Stream] with MonadCombine[Stream] with CoflatMap[Stream] = @@ -58,6 +59,11 @@ trait StreamInstances { override def isEmpty[A](fa: Stream[A]): Boolean = fa.isEmpty } + implicit def streamShow[A: Show]: Show[Stream[A]] = + new Show[Stream[A]] { + def show(fa: Stream[A]): String = if(fa.isEmpty) "Stream()" else s"Stream(${fa.head.show}, ?)" + } + // TODO: eventually use algebra's instances (which will deal with // implicit priority between Eq/PartialOrder/Order). diff --git a/tests/src/test/scala/cats/tests/StreamTests.scala b/tests/src/test/scala/cats/tests/StreamTests.scala index fa1080f06b..828fed2ddb 100644 --- a/tests/src/test/scala/cats/tests/StreamTests.scala +++ b/tests/src/test/scala/cats/tests/StreamTests.scala @@ -16,4 +16,26 @@ class StreamTests extends CatsSuite { checkAll("Stream[Int] with Option", TraverseTests[Stream].traverse[Int, Int, Int, List[Int], Option, Option]) checkAll("Traverse[Stream]", SerializableTests.serializable(Traverse[Stream])) + + test("show") { + Stream(1, 2, 3).show should === ("Stream(1, ?)") + Stream.empty[Int].show should === ("Stream()") + } + + test("Show[Stream] is referentially transparent, unlike Stream.toString") { + forAll { stream: Stream[Int] => + if (!stream.isEmpty) { + val unevaluatedStream = stream map identity + val initialShow = unevaluatedStream.show + + // Evaluating the tail can cause Stream.toString to return different values, + // depending on the internal state of the Stream. Show[Stream] should return + // consistent values independent of internal state. + unevaluatedStream.tail + initialShow should === (unevaluatedStream.show) + } else { + stream.show should === (stream.toString) + } + } + } }