代码之家  ›  专栏  ›  技术社区  ›  muhuk

如何匹配没有特定类型类实例的类型?[副本]

  •  3
  • muhuk  · 技术社区  · 8 年前

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

      // 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,不成形等)

    2 回复  |  直到 8 年前
        1
  •  5
  •   0__    8 年前

    有没有方法对类型绑定求反?

    不语法 [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
  •  5
  •   Travis Brown    8 年前

    你可以自己滚:

    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
    }
    

    这感觉像是一个黑客,但它可以工作,人们一直在使用它。