Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
WTF?
trait Functor[F[_]]
object Functor {
implicit val OptionFunctor: Functor[Option] =
error("")
}
case class OptionT[F[+_], +A]
object OptionT {
implicit def OptionTFunctor[F[+_]](implicit F0: Functor[F]): Functor[({type λ[α] = OptionT[F, α]})#λ] =
error("")
}
trait TTT {
// fine
val a = implicitly[Functor[Option]]
// fine
val b = implicitly[Functor[({type lam[+a]=OptionT[Option, a]})#lam]]
// not fine
val c = implicitly[Functor[({type lam[+a]=OptionT[({type l[+b]=OptionT[Option, b]})#l, a]})#lam]]
}
@tonymorris

This comment has been minimized.

Copy link
Owner Author

@tonymorris tonymorris commented Jul 20, 2012

case class Wibb[A]

trait Functor[F[_]]

object Functor {
  implicit val OptionFunctor: Functor[Wibb] =
    error("")

}

case class OptionT[F[_], A]

object OptionT {
  implicit def OptionTFunctor[F[_]](implicit F0: Functor[F]): Functor[({type λ[α] = OptionT[F, α]})#λ] =
    error("")
}

trait TTT {
  type Q[A] = OptionT[Wibb, A]
  type R[A] = OptionT[Q, A]
  type S[A] = OptionT[({type l[b]=OptionT[Wibb, b]})#l, A]

  // fine
  val a = implicitly[Functor[Wibb]]

  // fine
  val b = implicitly[Functor[({type lam[a]=OptionT[Wibb, a]})#lam]]

  // fine
  val c = implicitly[Functor[R]]

  // not fine
  val d = implicitly[Functor[S]]
}
@mergeconflict

This comment has been minimized.

Copy link

@mergeconflict mergeconflict commented Jul 20, 2012

I suspect it's to do with SLS §7.2 (p. 108), where the compiler is trying to avoid looping, but I'm not sure I'm understanding the spec correctly. Well, I'm also not sure the compiler understands the spec correctly, but that's another story...

Suffice it to say:

Yusuf: An Option within an OptionT? Two levels?
Cobb: Three.
Yusuf: Not possible. That many OptionTs within OptionTs would be too unstable.
Cobb: I've done it before. You just have to add a sedative.
Yusuf: A powerful sedative.

@mergeconflict

This comment has been minimized.

Copy link

@mergeconflict mergeconflict commented Jul 20, 2012

The following seems to work:

trait Functor[F[+_]]

object Functor {
  implicit val OptionFunctor: Functor[Option] = sys.error("")
}

class OptionT[F[_], +A]

object OptionT {
  implicit def OptionTFunctor[F[+_] : Functor]: Functor[({type λ[+α] = OptionT[F, α]})#λ] = sys.error("")
}

trait TTT {
  type Q[+A] = OptionT[Option, A]
  type R[+A] = OptionT[Q, A]
  type S[+A] = OptionT[R, A]

  val a = implicitly[Functor[Option]]
  val b = implicitly[Functor[Q]]
  val c = implicitly[Functor[R]]
  val d = implicitly[Functor[S]]
}

Trying to replace, for example:

type R[+A] = OptionT[({type l[+a] = Q[a]})#l, A]

causes the world to explode:

<console>:31: error: could not find implicit value for parameter e: Functor[TTT.this.R]
         val c = implicitly[Functor[R]]

This makes me believe that the way type lambdas are expressed as type refinements is running afoul of the definition of "core type." Again though, I don't really understand, this is just my most compelling hand-waving.

@retronym

This comment has been minimized.

Copy link

@retronym retronym commented Jul 20, 2012

Forget implicits for a moment; the problem is just type argument inference.

case class Wibb[A]

trait Functor[F[_]]

object TTT {
  val WibbFunctor: Functor[Wibb] =
    error("")

  def OptionTFunctor[F[_]](F0: Functor[F]): Functor[({type λ[α] = OptionT[F, α]})#λ] =
    error("")

  type S[A] = OptionT[({type l[b]=OptionT[Wibb, b]})#l, A]

  // okay
  OptionTFunctor[({type l[b]=OptionT[Wibb, b]})#l](OptionTFunctor[Wibb](WibbFunctor)): Functor[S]

  // a bridge too far
  OptionTFunctor(OptionTFunctor[Wibb](WibbFunctor)): Functor[S]
}

({type l[b]=OptionT[Wibb, b]})#l will never be inferred.

@retronym

This comment has been minimized.

Copy link

@retronym retronym commented Jul 20, 2012

BTW, -Yinfer-debug is your friend at times like these.

@tonymorris

This comment has been minimized.

Copy link
Owner Author

@tonymorris tonymorris commented Jul 20, 2012

@retronym

This comment has been minimized.

Copy link

@retronym retronym commented Jul 20, 2012

Oh, I missed the key point of your example. It's an interesting one. A bit of a closer look at it:

case class Wibb[A]

trait Functor[F[_]]

object TTT {
  implicit val WibbFunctor: Functor[Wibb] =
    error("")

  implicit def OptionTFunctor[F[_]](implicit F0: Functor[F]): Functor[({type λ[α] = OptionT[F, α]})#λ] =
    error("")

  type Q[A] = OptionT[Wibb, A]
  type R[A] = OptionT[Q, A]
  type S[A] = OptionT[({type l[b]=OptionT[Wibb, b]})#l, A]

  // okay
  OptionTFunctor[({type l[b]=OptionT[Wibb, b]})#l](OptionTFunctor[Wibb](WibbFunctor)): Functor[S]
  OptionTFunctor[Q](OptionTFunctor(WibbFunctor)): Functor[R]
  implicitly[Functor[R]] // Infers [Q] !

  // a bridge too far
  // OptionTFunctor(OptionTFunctor[Wibb](WibbFunctor)): Functor[S]

  // Can't infer [Q]
  // OptionTFunctor(OptionTFunctor(WibbFunctor)): Functor[R]
}
@tonymorris

This comment has been minimized.

Copy link
Owner Author

@tonymorris tonymorris commented Jul 22, 2012

Yeah, that's exactly the point. I will hopefully take a look at it closely soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment