From f0497b5930c608799578e450c20084d0d90a0c99 Mon Sep 17 00:00:00 2001 From: Cody Allen Date: Fri, 6 Nov 2015 08:15:50 -0500 Subject: [PATCH] Add Show for Option and OptionT The OptionT Show instance just uses the Show instance for the wrapped `F[Option[A]]` as opposed to wrapping it in `OptionT(...)`. This is to match the current behavior of `XorT`, but I'm wondering if that's something we would want to change on both. It seems to me like the Show output should reflect the fact that the value is wrapped in a monad transformer, but I don't have particularly strong feelings about this. --- core/src/main/scala/cats/data/OptionT.scala | 5 +++++ core/src/main/scala/cats/std/option.scala | 8 ++++++++ tests/src/test/scala/cats/tests/OptionTTests.scala | 5 +++++ tests/src/test/scala/cats/tests/OptionTests.scala | 9 +++++++++ 4 files changed, 27 insertions(+) diff --git a/core/src/main/scala/cats/data/OptionT.scala b/core/src/main/scala/cats/data/OptionT.scala index 75d77e1812..201afa2bf6 100644 --- a/core/src/main/scala/cats/data/OptionT.scala +++ b/core/src/main/scala/cats/data/OptionT.scala @@ -88,6 +88,8 @@ final case class OptionT[F[_], A](value: F[Option[A]]) { def toLeft[R](right: => R)(implicit F: Functor[F]): XorT[F, A, R] = XorT(cata(Xor.Right(right), Xor.Left.apply)) + + def show(implicit F: Show[F[Option[A]]]): String = F.show(value) } object OptionT extends OptionTInstances { @@ -138,4 +140,7 @@ trait OptionTInstances extends OptionTInstances1 { } implicit def optionTEq[F[_], A](implicit FA: Eq[F[Option[A]]]): Eq[OptionT[F, A]] = FA.on(_.value) + + implicit def optionTShow[F[_], A](implicit F: Show[F[Option[A]]]): Show[OptionT[F, A]] = + functor.Contravariant[Show].contramap(F)(_.value) } diff --git a/core/src/main/scala/cats/std/option.scala b/core/src/main/scala/cats/std/option.scala index 9eab6351c3..748bba181c 100644 --- a/core/src/main/scala/cats/std/option.scala +++ b/core/src/main/scala/cats/std/option.scala @@ -79,6 +79,14 @@ trait OptionInstances extends OptionInstances1 { if (y.isDefined) -1 else 0 } } + + implicit def showOption[A](implicit A: Show[A]): Show[Option[A]] = + new Show[Option[A]] { + def show(fa: Option[A]): String = fa match { + case Some(a) => s"Some(${A.show(a)})" + case None => "None" + } + } } trait OptionInstances1 extends OptionInstances2 { diff --git a/tests/src/test/scala/cats/tests/OptionTTests.scala b/tests/src/test/scala/cats/tests/OptionTTests.scala index fe2174d7ac..5c509ef6c6 100644 --- a/tests/src/test/scala/cats/tests/OptionTTests.scala +++ b/tests/src/test/scala/cats/tests/OptionTTests.scala @@ -111,6 +111,11 @@ class OptionTTests extends CatsSuite { } } + test("show"){ + val xor: String Xor Option[Int] = Xor.right(Some(1)) + OptionT[Xor[String, ?], Int](xor).show should === ("Xor.Right(Some(1))") + } + checkAll("OptionT[List, Int]", MonadCombineTests[OptionT[List, ?]].monad[Int, Int, Int]) checkAll("MonadOptionT[List, ?]]", SerializableTests.serializable(Monad[OptionT[List, ?]])) diff --git a/tests/src/test/scala/cats/tests/OptionTests.scala b/tests/src/test/scala/cats/tests/OptionTests.scala index 86eab0f910..72702002ad 100644 --- a/tests/src/test/scala/cats/tests/OptionTests.scala +++ b/tests/src/test/scala/cats/tests/OptionTests.scala @@ -12,4 +12,13 @@ class OptionTests extends CatsSuite { checkAll("Option[Int] with Option", TraverseTests[Option].traverse[Int, Int, Int, Int, Option, Option]) checkAll("Traverse[Option]", SerializableTests.serializable(Traverse[Option])) + + test("show") { + none[Int].show should === ("None") + 1.some.show should === ("Some(1)") + + forAll { fs: Option[String] => + fs.show should === (fs.toString) + } + } }