Awesome
implicit-dependent-type <a href="http://thoughtworks.com/"><img align="right" src="https://www.thoughtworks.com/imgs/tw-logo.png" title="ThoughtWorks" height="15"/></a>
implicit-dependent-type is a Scala compiler plugin that resolves dependent types from implicit type classes, especially useful when working with shapeless or other type-level programming libraries.
Setup
addCompilerPlugin("com.thoughtworks.implicit-dependent-type" %% "implicit-dependent-type" % "latest.release")
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)
libraryDependencies += "com.chuusai" %% "shapeless" % "latest.release"
Foo[Bar]##Baz
syntax
This plugin provides a syntactic sugar that substitutes all Foo[Bar]##Baz
with shapeless.the.`Foo[Bar]`.Baz
,
which inlines resolved implicit type classes into type declaration positions.
import shapeless._
final case class Foo(bar: Int, baz: String)
val hlistForFoo: Generic[Foo]##Repr = 1 :: "xxx" :: HNil
val foo: Foo = Generic[Foo].from(hlistForFoo)
The above example equals to the following code:
import shapeless._
final case class Foo(bar: Int, baz: String)
val g = Generic[Foo]
val hlistForFoo: g.Repr = 1 :: "xxx" :: HNil
val foo: Foo = Generic[Foo].from(hlistForFoo)
As you see, without this plugin, Generic[Foo]
is not a stable value,
thus it is unable to be placed at a type position.
You will have to assign it to a temporary variable g
.
This plugin resolves this problem.
Foo @Bar
syntax (since 2.0)
Another syntactic sugar provided by this plugin is Foo @Bar
, which will be converted to shapeless.the.`Bar[Foo]`.`@`
.
For example:
trait GetElement[A] {
type `@`
}
implicit def getArrayElement[Element] = new GetElement[Array[Element]] {
override type `@` = Element
}
implicit def getSeqElement[Element] = new GetElement[Seq[Element]] {
override type `@` = Element
}
val i: Array[Int] @GetElement = 1 // OK
val s: Seq[String] @GetElement = "text" // OK
val d: Option[Double] @GetElement = 0.5 // Does not compile because no implicit GetElement[Option[Double]] found
In the above example, @GetElement
acts as a type level function, calculating the element type of the given type.
Note that the Foo @Bar
syntax only applied if Bar
starts with an upper case character.
Thus, this plugin does not affect built-in annotations like @specialize
, @cps
or @suspendable
because they start with a lower case character.