Skip to content

Commit

Permalink
Merge pull request #4600 from pomadchin/feature/scala3-functionK-lift…
Browse files Browse the repository at this point in the history
…-port

Expose FunctionK.liftFunction as a part of the Scala 3 API
  • Loading branch information
satorg committed May 13, 2024
2 parents dfd9559 + baec5e0 commit 6de2a67
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 19 deletions.
19 changes: 1 addition & 18 deletions core/src/main/scala-2/cats/arrow/FunctionKMacros.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ package arrow

import scala.reflect.macros.blackbox

private[arrow] class FunctionKMacroMethods {
protected type τ[F[_], G[_]]
private[arrow] class FunctionKMacroMethods extends FunctionKLift {

/**
* Lifts function `f` of `F[A] => G[A]` into a `FunctionK[F, G]`.
Expand All @@ -48,22 +47,6 @@ private[arrow] class FunctionKMacroMethods {
*/
def lift[F[_], G[_]](f: (F[α] => G[α]) forSome { type α }): FunctionK[F, G] =
macro FunctionKMacros.lift[F, G]

/**
* Lifts function `f` of `F[A] => G[A]` into a `FunctionK[F, G]`.
*
* {{{
* def headOption[A](list: List[A]): Option[A] = list.headOption
* val lifted = FunctionK.liftFunction[List, Option](headOption)
* }}}
*
* Note: The weird `τ[F, G]` parameter is there to compensate for
* the lack of polymorphic function types in Scala 2.
*/
def liftFunction[F[_], G[_]](f: F[τ[F, G]] => G[τ[F, G]]): FunctionK[F, G] =
new FunctionK[F, G] {
def apply[A](fa: F[A]): G[A] = f.asInstanceOf[F[A] => G[A]](fa)
}
}

private[arrow] object FunctionKMacros {
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala-3/cats/arrow/FunctionKMacros.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
package cats
package arrow

private[arrow] class FunctionKMacroMethods {
private[arrow] class FunctionKMacroMethods extends FunctionKLift {

/**
* Lifts function `f` of `[X] => F[X] => G[X]` into a `FunctionK[F, G]`.
Expand Down
45 changes: 45 additions & 0 deletions core/src/main/scala/cats/arrow/FunctionKLift.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2015 Typelevel
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

package cats
package arrow

private[arrow] trait FunctionKLift {
protected type τ[F[_], G[_]]

/**
* Lifts function `f` of `F[A] => G[A]` into a `FunctionK[F, G]`.
*
* {{{
* def headOption[A](list: List[A]): Option[A] = list.headOption
* val lifted = FunctionK.liftFunction[List, Option](headOption)
* }}}
*
* Note: The weird `τ[F, G]` parameter is there to compensate for
* the lack of polymorphic function types in Scala 2.
*
* It is present in the Scala 3 API to simplify cross-compilation.
*/
def liftFunction[F[_], G[_]](f: F[τ[F, G]] => G[τ[F, G]]): FunctionK[F, G] =
new FunctionK[F, G] {
def apply[A](fa: F[A]): G[A] = f.asInstanceOf[F[A] => G[A]](fa)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,12 @@ class FunctionKLiftSuite extends CatsSuite {
assert(fHeadOption(a) === a.headOption)
}
}

test("lift a function directly using Scala 2 compatible syntax") {
def headOption[A](list: List[A]): Option[A] = list.headOption
val fHeadOption = FunctionK.liftFunction[List, Option](headOption)
forAll { (a: List[Int]) =>
assert(fHeadOption(a) === a.headOption)
}
}
}

0 comments on commit 6de2a67

Please sign in to comment.