From 1e8a4eaecf1195eda761fb7da94ada0660964338 Mon Sep 17 00:00:00 2001 From: "Mike (stew) O'Connor" Date: Wed, 14 Oct 2015 22:56:21 -0700 Subject: [PATCH] Add new shapes to Unapply This commit adds Unapply shapes which will match a datum with a type in the shape F[X[_], Y] with a typeclass expecting a F[_] Thanks to @smungee who noticed that apply syntax was not working with FreeApplicative because of this. --- core/src/main/scala/cats/Unapply.scala | 31 +++++++++++++++++++ .../test/scala/cats/tests/UnapplyTests.scala | 10 ++++++ 2 files changed, 41 insertions(+) diff --git a/core/src/main/scala/cats/Unapply.scala b/core/src/main/scala/cats/Unapply.scala index 371cc7ce57..a2ea0c1e58 100644 --- a/core/src/main/scala/cats/Unapply.scala +++ b/core/src/main/scala/cats/Unapply.scala @@ -65,6 +65,20 @@ sealed abstract class Unapply2Instances extends Unapply3Instances { type A = B } + // the type we will instantiate when we find a type class instance + // for a type in the shape F[_,_[_]] when we fix the left type + type Aux2LeftK[TC[_[_]], FA, F[_,_[_]], AA, BX[_]] = Unapply[TC, FA] { + type M[X] = F[X,BX] + type A = AA + } + + // the type we will instantiate when we find a type class instance + // for a type in the shape F[_[_],_] when we fix the right type, + type Aux2RightK[TC[_[_]], MA, F[_[_],_], AX[_], B] = Unapply[TC, MA] { + type M[X] = F[AX,X] + type A = B + } + implicit def unapply2left[TC[_[_]], F[_,_], AA, B](implicit tc: TC[F[?,B]]): Aux2Left[TC,F[AA,B], F, AA, B] = new Unapply[TC, F[AA,B]] { type M[X] = F[X, B] @@ -80,6 +94,23 @@ sealed abstract class Unapply2Instances extends Unapply3Instances { def subst: F[AA, B] => M[A] = identity } + + implicit def unapply2leftK[TC[_[_]], F[_,_[_]], AA, B[_]](implicit tc: TC[F[?,B]]): Aux2LeftK[TC,F[AA,B], F, AA, B] = new Unapply[TC, F[AA,B]] { + type M[X] = F[X, B] + type A = AA + def TC: TC[F[?, B]] = tc + def subst: F[AA, B] => M[A] = identity + } + + implicit def unapply2rightK[TC[_[_]], F[_[_],_], AA[_], B](implicit tc: TC[F[AA,?]]): Aux2RightK[TC,F[AA,B], F, AA, B] = new Unapply[TC, F[AA,B]] { + type M[X] = F[AA, X] + type A = B + def TC: TC[F[AA, ?]] = tc + def subst: F[AA, B] => M[A] = identity + } + + + // STEW: I'm not sure why these Nothing cases are needed and aren't // just caught by the generic cases, I'd love for someone to figure // that out and report back. diff --git a/tests/src/test/scala/cats/tests/UnapplyTests.scala b/tests/src/test/scala/cats/tests/UnapplyTests.scala index 4ec202b540..c5f687ff70 100644 --- a/tests/src/test/scala/cats/tests/UnapplyTests.scala +++ b/tests/src/test/scala/cats/tests/UnapplyTests.scala @@ -16,4 +16,14 @@ class UnapplyTests extends CatsSuite { val x = Traverse[List].traverseU(List(1,2,3))(Xor.right(_)) (x: String Xor List[Int]) should === (Xor.right(List(1,2,3))) } + + test("Unapply works for F[_[_],_] with the left fixed") { + val x: OptionT[List, Int] = OptionT(List(Option(1), Option(2))) + val y: OptionT[List, Int] = OptionT(List(Option(3), Option(4))) + + val z: List[Option[(Int,Int)]] = (x |@| y).tupled.value + + z should be (List(Option((1,3)), Option((1,4)), + Option((2,3)), Option((2,4)))) + } }