如何匹配没有特定类型类实例的类型?

muh*_*huk 3 scala typeclass type-bounds

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

  // 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 = ???
Run Code Online (Sandbox Code Playgroud)

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

有没有办法否定类型绑定?一种使用!:compile编写函数的方法?

(我想在香草Scala中做这个,没有scalaz,没有形状等)

0__*_*0__ 5

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

没有!语法[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]
Run Code Online (Sandbox Code Playgroud)

例:

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
Run Code Online (Sandbox Code Playgroud)

但是,我强烈建议不要这样做,因为implicits和类类的主要观点是如果某些内容不在范围内,则显式编译器失败.这样您将始终能够编译,但无法保证您正确地将特定类型类引入范围.


Tra*_*own 5

你可以自己动手:

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] {}
}
Run Code Online (Sandbox Code Playgroud)

然后:

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]]
                 ^
Run Code Online (Sandbox Code Playgroud)

在许多情况下,你可以使用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
}
Run Code Online (Sandbox Code Playgroud)

这感觉就像一个黑客,但它的工作原理和人们一直使用它.