在Scala2中,如何使用implant实现匹配类型?

tp5buhyn  于 5个月前  发布在  Scala
关注(0)|答案(1)|浏览(59)

我尝试使用隐式实现匹配类型,这里是一个工作示例:

{
    trait FnUnpack[F <: Function1[?, ?]] {
      type II
      type OO
    }

    object FnUnpack {

      implicit def only[I, O]: FnUnpack[I => O] { type II = I; type OO = O } =
        null
    }

    val u = summon[FnUnpack[Int => String]]
    summon[u.II =:= Int]
  }

字符串
但是稍微改变一下,使它更容易被Function 1的子类接受,我可以很容易地打破它:

{
    trait FnUnpack[-F <: Function1[?, ?]] {
      type II
      type OO
    }

    object FnUnpack {

      implicit def only[I, O]: FnUnpack[I => O] { type II = I; type OO = O } =
        null
    }

    val u = summon[FnUnpack[Int => String]]
    summon[u.II =:= Int]
//[Error] XXX.scala:36:11: Cannot prove that u.II =:= Int.

  }


如果启用了splain插件,编译器会自动假定u.II = Nothing

Nothing (reduced from) { u.II } =:= Int
  Cannot prove that u.II =:= Int.


看起来,一个逆变标记完全破坏了隐式搜索算法!这是怎么发生的,需要做些什么来修复它?

lsmd5eda

lsmd5eda1#

为了使FnUnpack更容易被Function1的子类接受,而不破坏隐式解析机制,您可以使用隐式定义中的类型绑定,而不是将方差应用于trait本身。这样,隐式示例可以更灵活地接受什么,而不会影响类型成员的推断。

trait FnUnpack[F] {
  type II
  type OO
}

object FnUnpack {
  // Use an implicit def with a type bound
  implicit def only[F <: Function1[I, O], I, O]: FnUnpack[F] { type II = I; type OO = O } = null
}

// Test with a function type
val u = summon[FnUnpack[Int => String]]
summon[u.II =:= Int] // Should compile without issues

字符串

**更新:**对于Scala 2,类型推断不如Scala 3强大,我们需要为编译器提供更多指导。这里的挑战是Scala 2的类型推断在此特定上下文中难以推断类型成员。

一种解决方法是使用带有类型参数而不是类型成员的类型类。

trait FnUnpack[F, II, OO]

object FnUnpack {
  // Define an implicit def for Function1 types
  implicit def only[I, O]: FnUnpack[I => O, I, O] = new FnUnpack[I => O, I, O] {}

  // Helper method to summon FnUnpack instances
  def apply[F, II, OO](implicit ev: FnUnpack[F, II, OO]): FnUnpack[F, II, OO] = ev
}

// Now you can summon the instance for Int => String and check the types
val u = FnUnpack[Int => String, Int, String]

相关问题