shapeless.Lazy
実装
implicitly
のためにmacroで実装される。quasiquoteを使うと
trait Lazy[T] { val value: T } object Lazy { implicit def mkLazy[T]: Lazy[T] = macro mkLazyImpl[T] def mkLazyImpl[T](c: Context)(t: c.WeakTypeTag[T]): c.Tree = { import c.universe._ val recName = TermName(c.freshName) q""" new Lazy[${t.tpe}] { implicit val $recName: Lazy[${t.tpe}] = this override lazy val value: ${t.tpe} = implicitly[${t.tpe}] } """ } }
のような感じになっている。*2
$recName
がミソで、implicitly
のargumentの探索の過程で、再びLazy[T]
が必要になれば、
$recName
が採用されて探索はストップする。*3
例
trait Undefined implicit def mkUndefined(implicit x: Lazy[Undefined]): Undefined = new Undefined {} def myImplicitly[T](implicit x: T): T = x myImplicitly[Undefined]
最終的に、$recName
がx
に渡されて探索はストップする。
どういうわけか、標準のimplicitly
を使うとdivergingしてしまう。