Pregunta

This is code:

object inc extends Poly1 {
  implicit val caseInt = at[Int]{_ + 1}
  implicit def default[T] = at[T](identity)
}

println(List(3).map(inc))
println(List("3").map(inc))

My question is how poly1 can be blended into map function. TraversableLike defines map signature. Map[B, That](f: A => B), "That" will be provided by CanBuildFrom, so my confusion is about A => B, I look at the source code of Poly1, there are no mapping, how this List(3).map(inc) works ?

¿Fue útil?

Solución

This is explained at http://www.chuusai.com/2012/05/10/shapeless-polymorphic-function-values-2/ ; look for the part about polyToMono.

The core idea is that although Poly1 cannot extend scala.Function1, Shapeless provides an implicit conversion so that a polymorphic function can be provided in situations where an ordinary monomorphic function is expected, such as when calling List.map.

There is some extra trickiness needed to make it work both for ordinary types like Int (as in your example) and parameterized types. This is done by wrapping Int as Id[Int] (where Id is the type-level identity function), reducing the un-parameterized case to the parameterized case.

But those blog posts are from 2012 and things are sometimes different in the Shapeless 2.0 that we have today in 2014. When in doubt, consult the Shapeless 2.0 source code.

The 2.0 source doesn't have anything called polyToMono. Where did it go?

As it happens, reify is helpful for investigating these "how the hell does this even compile?" type questions:

scala> reflect.runtime.universe.reify(List(3).map(inc))
res1: reflect.runtime.universe.Expr[List[inc.caseInt.Result]] =
  Expr[List[inc.caseInt.Result]](
    List.apply(3).map(Poly.inst1($read.inc)(this.inc.caseInt))(
      List.canBuildFrom))

So Poly.inst1 seems to be the key here, and yeah, over at https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/poly.scala we see:

implicit def inst1[F[_], G[_], T](f : F ~> G) : F[T] => G[T] = f(_)

which is just polyToMono from the blog post, renamed.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top