forked from typelevel/kind-projector
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add option to use underscore symbol
_
instead of *
to define anon…
…ymous type lambdas The syntax roughly follows the [proposed new syntax for wildcards and placeholders](https://dotty.epfl.ch/docs/reference/changed-features/wildcards.html#migration-strategy) for Scala 3.2+ and is designed to allow cross-compilation of libraries between Scala 2 and Scala 3 while using the new Scala 3 syntax for both versions. To enable this mode, add `-P:kind-projector:underscore-placeholders` to your scalac command-line. In sbt you may do this as follows: ```scala ThisBuild / scalacOptions += "-P:kind-projector:underscore-placeholders" ``` This mode is designed to be used with scalac versions `2.12.14`+ and `2.13.6`+, these versions add an the ability to use `?` as the existential type wildcard ([scala/scala#9560](scala/scala#9560)), allowing to repurpose the underscore without losing the ability to write existential types. It is not advised that you use this mode with older versions of scalac or without `-Xsource:3` flag, since you will lose the underscore syntax entirely. Here are a few examples: ```scala Tuple2[_, Double] // equivalent to: type R[A] = Tuple2[A, Double] Either[Int, +_] // equivalent to: type R[+A] = Either[Int, A] Function2[-_, Long, +_] // equivalent to: type R[-A, +B] = Function2[A, Long, B] EitherT[_[_], Int, _] // equivalent to: type R[F[_], B] = EitherT[F, Int, B] ``` Examples with `-Xsource:3`'s `?`-wildcard: ```scala Tuple2[_, ?] // equivalent to: type R[A] = Tuple2[A, x] forSome { type x } Either[?, +_] // equivalent to: type R[+A] = Either[x, A] forSome { type x } Function2[-_, ?, +_] // equivalent to: type R[-A, +B] = Function2[A, x, B] forSome { type x } EitherT[_[_], ?, _] // equivalent to: type R[F[_], B] = EitherT[F, x, B] forSome { type x } ```
- Loading branch information
Showing
12 changed files
with
367 additions
and
7 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package d_m | ||
|
||
import scala.tools.nsc.plugins.Plugin | ||
|
||
trait PluginOptionsCompat { | ||
def pluginOptions(plugin: Plugin) = plugin.options | ||
} | ||
|
||
//compatibility stub | ||
trait PluginCompat |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package d_m | ||
|
||
import scala.tools.nsc.plugins.Plugin | ||
|
||
trait PluginOptionsCompat { | ||
def pluginOptions(plugin: Plugin) = plugin.asInstanceOf[PluginCompat].options | ||
} | ||
|
||
trait PluginCompat extends Plugin { | ||
var options: List[String] = _ | ||
override def processOptions(options: List[String], error: String => Unit): Unit = { | ||
this.options = options | ||
init(options, error) | ||
} | ||
def init(options: List[String], error: String => Unit): Boolean | ||
} |
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package underscores | ||
|
||
trait Functor[M[_]] { | ||
def fmap[A, B](fa: M[A])(f: A => B): M[B] | ||
} | ||
|
||
class EitherRightFunctor[L] extends Functor[Either[L, _]] { | ||
def fmap[A, B](fa: Either[L, A])(f: A => B): Either[L, B] = | ||
fa match { | ||
case Right(a) => Right(f(a)) | ||
case Left(l) => Left(l) | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package underscores | ||
|
||
trait ~~>[A[_[_]], B[_[_]]] { | ||
def apply[X[_]](a: A[X]): B[X] | ||
} | ||
|
||
trait Bifunctor[F[_[_[_]], _[_[_]]]] { | ||
def bimap[A[_[_]], B[_[_]], C[_[_]], D[_[_]]](fab: F[A, B])(f: A ~~> C, g: B ~~> D): F[C, D] | ||
} | ||
|
||
final case class Coproduct[A[_[_]], B[_[_]], X[_]](run: Either[A[X], B[X]]) | ||
|
||
object Coproduct { | ||
def coproductBifunctor[X[_]]: Bifunctor[Coproduct[_[_[_]], _[_[_]], X]] = | ||
new Bifunctor[Coproduct[_[_[_]], _[_[_]], X]] { | ||
def bimap[A[_[_]], B[_[_]], C[_[_]], D[_[_]]](abx: Coproduct[A, B, X])(f: A ~~> C, g: B ~~> D): Coproduct[C, D, X] = | ||
abx.run match { | ||
case Left(ax) => Coproduct(Left(f(ax))) | ||
case Right(bx) => Coproduct(Right(g(bx))) | ||
} | ||
} | ||
def test[X[_]]: Bifunctor[({ type L[F[_[_]], G[_[_]]] = Coproduct[F, G, X] })#L] = coproductBifunctor[X] | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package underscores | ||
|
||
// // From https://github.com/non/kind-projector/issues/20 | ||
// import scala.language.higherKinds | ||
|
||
object KindProjectorWarnings { | ||
trait Foo[F[_], A] | ||
trait Bar[A, B] | ||
|
||
def f[G[_]]: Unit = () | ||
|
||
f[Foo[Bar[Int, _], _]] // shadowing warning | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package underscores | ||
|
||
trait ~>[-F[_], +G[_]] { | ||
def apply[A](x: F[A]): G[A] | ||
} | ||
trait ~>>[-F[_], +G[_]] { | ||
def dingo[B](x: F[B]): G[B] | ||
} | ||
final case class Const[A, B](getConst: A) | ||
|
||
class PolyLambdas { | ||
type ToSelf[F[_]] = F ~> F | ||
|
||
val kf1 = Lambda[Option ~> Vector](_.iterator.toVector) | ||
|
||
val kf2 = λ[Vector ~> Option] { | ||
case Vector(x) => Some(x) | ||
case _ => None | ||
} | ||
|
||
val kf3 = λ[ToSelf[Vector]](_.reverse) | ||
|
||
val kf4 = λ[Option ~>> Option].dingo(_ flatMap (_ => None)) | ||
|
||
val kf5 = λ[Map[_, Int] ~> Map[_, Long]](_.map { case (k, v) => (k, v.toLong) }.toMap) | ||
|
||
val kf6 = λ[ToSelf[Map[_, Int]]](_.map { case (k, v) => (k, v * 2) }.toMap) | ||
|
||
implicit class FGOps[F[_], A](x: F[A]) { | ||
def ntMap[G[_]](kf: F ~> G): G[A] = kf(x) | ||
} | ||
|
||
// Scala won't infer the unary type constructor alias from a | ||
// tuple. I'm not sure how it even could, so we'll let it slide. | ||
type PairWithInt[A] = (A, Int) | ||
def mkPair[A](x: A, y: Int): PairWithInt[A] = x -> y | ||
val pairMap = λ[ToSelf[PairWithInt]] { case (k, v) => (k, v * 2) } | ||
val tupleTakeFirst = λ[λ[A => (A, Int)] ~> List](x => List(x._1)) | ||
|
||
// All these formulations should be equivalent. | ||
def const1[A] = λ[ToSelf[Const[A, _]]](x => x) | ||
def const2[A] : ToSelf[Const[A, _]] = λ[Const[A, _] ~> Const[A, _]](x => x) | ||
def const3[A] : Const[A, _] ~> Const[A, _] = λ[ToSelf[Const[A, _]]](x => x) | ||
def const4[A] = λ[Const[A, _] ~> Const[A, _]](x => x) | ||
def const5[A] : ToSelf[Const[A, _]] = λ[ToSelf[λ[B => Const[A, B]]]](x => x) | ||
def const6[A] : Const[A, _] ~> Const[A, _] = λ[ToSelf[λ[B => Const[A, B]]]](x => x) | ||
|
||
@org.junit.Test | ||
def polylambda(): Unit = { | ||
assert(kf1(None) == Vector()) | ||
assert(kf1(Some("a")) == Vector("a")) | ||
assert(kf1(Some(5d)) == Vector(5d)) | ||
assert(kf2(Vector(5)) == Some(5)) | ||
assert(kf3(Vector(1, 2)) == Vector(2, 1)) | ||
assert(kf4.dingo(Some(5)) == None) | ||
assert(kf5(Map("a" -> 5)) == Map("a" -> 5)) | ||
assert(kf6(Map("a" -> 5)) == Map("a" -> 10)) | ||
|
||
assert((mkPair("a", 1) ntMap pairMap) == ("a" -> 2)) | ||
assert((mkPair(Some(true), 1) ntMap pairMap) == (Some(true) -> 2)) | ||
|
||
assert(mkPair('a', 1).ntMap(tupleTakeFirst) == List('a')) | ||
// flatten works, whereas it would be a static error in the | ||
// line above. That's pretty poly! | ||
assert(mkPair(Some(true), 1).ntMap(tupleTakeFirst).flatten == List(true)) | ||
} | ||
} |
Oops, something went wrong.