tl; dr:我该如何做以下类似的组成代码:def notFunctor[M[_] : Not[Functor]](m: M[_]) = s"$m is not a functor"'Not[Functor]',是这里的组成部分。当提供的'm'不是函子时,我希望它成功,否则使编译器失败。已解决:跳过其余问题,然后直接转到下面的答案。粗略地说,我要完成的工作是“负面证据”。伪代码如下所示:// type class for obtaining serialization size in bytes.trait SizeOf[A] { def sizeOf(a: A): Long }// type class specialized for types whose size may vary between instancestrait VarSizeOf[A] extends SizeOf[A]// type class specialized for types whose elements share the same size (e.g. Int)trait FixedSizeOf[A] extends SizeOf[A] { def fixedSize: Long def sizeOf(a: A) = fixedSize}// SizeOf for container with fixed-sized elements and Length (using scalaz.Length)implicit def fixedSizeOf[T[_] : Length, A : FixedSizeOf] = new VarSizeOf[T[A]] { def sizeOf(as: T[A]) = ... // length(as) * sizeOf[A]}// SizeOf for container with scalaz.Foldable, and elements with VarSizeOfimplicit def foldSizeOf[T[_] : Foldable, A : SizeOf] = new VarSizeOf[T[A]] { def sizeOf(as: T[A]) = ... // foldMap(a => sizeOf(a))}请记住,fixedSizeOf()在相关时更可取,因为它可以节省遍历集合的遍历。这样,对于仅定义Length(但未定义Foldable)的容器类型以及对于定义FixedSizeOf的元素,我们可以提高性能。对于其余情况,我们遍历集合并求和各个大小。我的问题是在为容器定义了Length和Foldable的同时为元素定义了FixedSizeOf的情况。这是一种非常常见的情况(例如:List[Int]都已定义)。例:scala> implicitly[SizeOf[List[Int]]].sizeOf(List(1,2,3))<console>:24: error: ambiguous implicit values: both method foldSizeOf of type [T[_], A](implicit evidence$1: scalaz.Foldable[T], implicit evidence$2: SizeOf[A])VarSizeOf[T[A]] and method fixedSizeOf of type [T[_], A](implicit evidence$1: scalaz.Length[T], implicit evidence$2: FixedSizeOf[A])VarSizeOf[T[A]] match expected type SizeOf[List[Int]] implicitly[SizeOf[List[Int]]].sizeOf(List(1,2,3))我想要的是仅在Foldable + Length组合不适用时才能够依赖FixedSizeOf类型类。为此,我可以将foldSizeOf()的定义更改为接受VarSizeOf元素:implicit def foldSizeOfVar[T[_] : Foldable, A : VarSizeOf] = // ...现在,我们必须填写有问题的部分,该部分涉及使用Foldable元素且未定义FixedSizeOf的Length容器。我不确定该如何处理,但伪代码如下所示:implicit def foldSizeOfFixed[T[_] : Foldable : Not[Length], A : FixedSizeOf] = // ...显然,“ Not[Length]”是这里的组成部分。我知道的部分解决方案1)为低优先级隐式定义一个类,并将其扩展,如“ object Predef extends LowPriorityImplicits”所示。可以在父类中定义最后一个隐式(foldSizeOfFixed()),并将其替换为后代类。我对该选项不感兴趣,因为我希望最终能够支持SizeOf的递归使用,这将防止低优先级基类中的隐式依赖子类中的隐式(是我在此处的理解)正确吗?编辑:错误!从子类的上下文中进行隐式查找是可行的解决方案!)2)一种更粗略的方法是依赖Option[TypeClass](例如:Option[Length[List]]。我可以写一些这样的隐式代码,即选择Foldable和SizeOf为必选内容,并选择Length和为可选,如果可用,则依赖后者(来源:here)。这里的两个问题是缺乏模块性,并且在找不到相关类型类实例时会回退到运行时异常(可以使此示例与该解决方案一起使用,但这并不总是可能的)编辑:这是我能够使用可选隐式函数获得的最好的结果。还不存在:implicit def optionalTypeClass[TC](implicit tc: TC = null) = Option(tc)type OptionalLength[T[_]] = Option[Length[T]]type OptionalFixedSizeOf[T[_]] = Option[FixedSizeOf[T]]implicit def sizeOfContainer[ T[_] : Foldable : OptionalLength, A : SizeOf : OptionalFixedSizeOf]: SizeOf[T[A]] = new SizeOf[T[A]] { def sizeOf(as: T[A]) = { // optionally calculate using Length + FixedSizeOf is possible val fixedLength = for { lengthOf <- implicitly[OptionalLength[T]] sizeOf <- implicitly[OptionalFixedSizeOf[A]] } yield lengthOf.length(as) * sizeOf.fixedSize // otherwise fall back to Foldable fixedLength.getOrElse { val foldable = implicitly[Foldable[T]] val sizeOf = implicitly[SizeOf[A]] foldable.foldMap(as)(a => sizeOf.sizeOf(a)) } }}除非这与以前的FixedSizeOf冲突,但这仍然是必需的。感谢您的帮助或观点:-) (adsbygoogle = window.adsbygoogle || []).push({}); 最佳答案 我最终使用基于歧义的解决方案解决了这一问题,该解决方案不需要使用继承来进行优先级排序。这是我对此进行概括的尝试。我们使用类型Not[A]构造否定类型类:import scala.language.higherKindstrait Not[A]trait Monoid[_] // or import scalaz._, Scalaz._type NotMonoid[A] = Not[Monoid[A]]trait Functor[_[_]] // or import scalaz._, Scalaz._type NotFunctor[M[_]] = Not[Functor[M]]...然后可以用作上下文范围:def foo[T: NotMonoid] = ...我们通过确保Not [A]的每个有效表达式将至少获取一个隐式实例来进行操作。implicit def notA[A, TC[_]] = new Not[TC[A]] {}该实例称为'notA'-'not',因为如果它是为'Not [TC [A]]'找到的唯一实例,那么将发现否定类型类适用;通常在处理扁平类型(例如Int)的方法后附加“ A”。现在,我们引入了一种歧义,以消除应用了不期望的类型类的情况:implicit def notNotA[A : TC, TC[_]] = new Not[TC[A]] {}这几乎与'NotA'完全相同,除了这里我们只对隐式作用域中存在由'TC'指定的类型类实例的类型感兴趣。该实例名为“ notNotA”,因为仅匹配查找的隐式实例,它将与“ notA”产生歧义,从而使隐式搜索失败(这是我们的目标)。让我们来看一个用法示例。我们将从上面使用'NotMonoid'否定类型类:implicitly[NotMonoid[java.io.File]] // succeedsimplicitly[NotMonoid[Int]] // failsdef showIfNotMonoid[A: NotMonoid](a: A) = a.toStringshowIfNotMonoid(3) // fails, good!showIfNotMonoid(scala.Console) // succeeds for anything that isn't a Monoid到目前为止,一切都很好!但是,上述方案尚不支持形状为M [_]的类型和形状类型为TC [_ [_]]的类型类。我们也为它们添加隐式:implicit def notM[M[_], TC[_[_]]] = new Not[TC[M]] {}implicit def notNotM[M[_] : TC, TC[_[_]]] = new Not[TC[M]] {}implicitly[NotFunctor[List]] // failsimplicitly[NotFunctor[Class]] // succeeds很简单。请注意,Scalaz针对样板有一个变通办法,该样板是通过处理几种类型的形状产生的-查找“未应用”。我无法在基本情况下使用它(形状TC [_]的类型类,例如Monoid),即使它像魅力一样在TC [_ [_]](例如Functor)上工作,所以这个答案不能解决这个问题。如果有人感兴趣,这里是一个摘要中的所有内容:import scala.language.higherKindstrait Not[A]object Not { implicit def notA[A, TC[_]] = new Not[TC[A]] {} implicit def notNotA[A : TC, TC[_]] = new Not[TC[A]] {} implicit def notM[M[_], TC[_[_]]] = new Not[TC[M]] {} implicit def notNotM[M[_] : TC, TC[_[_]]] = new Not[TC[M]] {}}import Not._type NotNumeric[A] = Not[Numeric[A]]implicitly[NotNumeric[String]] // succeedsimplicitly[NotNumeric[Int]] // fails我在问题中要求的伪代码看起来像这样(实际代码):// NotFunctor[M[_]] declared abovedef notFunctor[M[_] : NotFunctor](m: M[_]) = s"$m is not a functor"更新:应用于隐式转换的类似技术:import scala.language.higherKindstrait Not[A]object Not { implicit def not[V[_], A](a: A) = new Not[V[A]] {} implicit def notNot[V[_], A <% V[A]](a: A) = new Not[V[A]] {}}现在,我们可以(例如)定义一个函数,该函数将仅在无法按顺序查看其类型时才接受值:def unordered[A <% Not[Ordered[A]]](a: A) = a (adsbygoogle = window.adsbygoogle || []).push({});
09-15 17:14