【问题标题】:How do I match types that don't have a specific typeclass instance? [duplicate]如何匹配没有特定类型类实例的类型? [复制]
【发布时间】:2016-06-01 19:19:55
【问题描述】:

我想为那些没有特定类型类实例的类型定义一些行为:

  // Given
  trait SomeTypeclass[T]

  // when we have implicit SomeTypeclass[T]
  def f[T: SomeTypeclass](x:T):Unit = ???
  // when we don't have instance
  def f[T !: SomeTypeclass](x: T):Unit = ???

我们可以处理类型类中的差异,但我需要创建额外的实例来支持一些通用行为。

有没有办法否定类型绑定?有办法让 !: 编译的函数?

(我想在原版 Scala 中执行此操作,没有 scalaz、shapeless 等)

【问题讨论】:

标签: scala typeclass type-bounds


【解决方案1】:

有没有办法否定类型绑定?

不!语法[T: SomeTypeclass] 只是(implicit val t: Sometypeclass[T]) 的简写,没有办法“否定”它。您可以重载该方法,但这会产生歧义。

但你可以“嵌套”类型类。

trait ExistsLowPri {
  implicit def no[A]: Exists[A] = Exists.No
}
object Exists extends ExistsLowPri {
  case class Yes[A](peer: A) extends Exists[A]
  case object No extends Exists[Nothing]

  implicit def yes[A](implicit peer: A): Exists[A] = new Yes(peer)
}
sealed trait Exists[+A]

例子:

trait Show[-A] {
  def show(x: A): String
}

def test[A](x: A)(implicit ex: Exists[Show[A]]): Unit = println(
  ex match {
    case Exists.Yes(s) => s.show(x)
    case Exists.No     => "(no string repr)"
  }
)

implicit object ShowBoolean extends Show[Boolean] {
  def show(b: Boolean) = if (b) "T" else "F" 
}

test(123)   // (no string repr)
test(true)  // T

但是,我强烈建议不要这样做,因为隐式和类型类的主要观点是,如果某些内容不在范围内,则会出现显式编译器故障。这样,您将始终能够编译,但不能保证您正确地将特定类型类带入范围。

【讨论】:

    【解决方案2】:

    您可以自己滚动:

    trait NoInstance[T[_], A]
    
    object NoInstance extends LowPriorityNoInstance {
      implicit def hasInstance0[T[_], A](implicit inst: T[A]): NoInstance[T, A] = ???
      implicit def hasInstance1[T[_], A](implicit inst: T[A]): NoInstance[T, A] = ???
    }
    
    class LowPriorityNoInstance {
      implicit def noInstance[T[_], A]: NoInstance[T, A] = new NoInstance[T, A] {}
    }
    

    然后:

    scala> implicitly[NoInstance[Ordering, List[Int]]]
    res4: NoInstance[Ordering,List[Int]] = LowPriorityNoInstance$$anon$1@5e1fc2aa
    
    scala> implicitly[NoInstance[Ordering, Int]]
    <console>:14: error: ambiguous implicit values:
     both method hasInstance0 in object NoInstance of type [T[_], A](implicit inst: T[A])NoInstance[T,A]
     and method hasInstance1 in object NoInstance of type [T[_], A](implicit inst: T[A])NoInstance[T,A]
     match expected type NoInstance[Ordering,Int]
           implicitly[NoInstance[Ordering, Int]]
                     ^
    

    在许多情况下,您可以使用 null 默认隐式参数技巧来避免这种情况:

    def f[T](x: T)(implicit stc: SomeTypeclass[T] = null): Unit = Option(stc) match {
      case Some(instance) => // do something in the case where we have an instance
      case None => // do something in the case where we don't have an instance
    }
    

    这感觉像是一种 hack,但它确实有效,而且人们一直在使用它。

    【讨论】:

    • 关于默认值= null的好点,没想到。
    • 这是一个不错的技巧。不确定我喜欢默认的null
    • 这些都是很好的答案。我接受了@0__,因为它看起来更惯用。 null 技巧也是一个轻量级的解决方案,谢谢。
    猜你喜欢
    • 1970-01-01
    • 2017-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多