tl;dr:我该如何做类似下面的代码:
def notFunctor[M[_] : Not[Functor]](m: M[_]) = s"$m is not a functor"
The 'Not[Functor]
',这是这里的组成部分。
我希望它在提供的“m”不是函子时成功,否则编译器将失败。
Solved:跳过问题的其余部分,直接进入下面的答案。
粗略地说,我想要完成的是“反面证据”。
伪代码看起来像这样:
// 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 instances
trait 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 VarSizeOf
implicit def foldSizeOf[T[_] : Foldable, A : SizeOf] = new VarSizeOf[T[A]] {
def sizeOf(as: T[A]) = ... // foldMap(a => sizeOf(a))
}
请记住fixedSizeOf()
在相关的情况下更可取,因为它节省了我们对集合的遍历。
这样,对于容器类型,只有Length
已定义(但未定义Foldable
),并且对于元素,其中FixedSizeOf
定义后,我们得到了改进的性能。
对于其余的情况,我们会检查集合并汇总各个尺寸。
我的问题是在两种情况下Length
and Foldable
为容器定义,并且FixedSizeOf
是为元素定义的。这是这里很常见的情况(例如:List[Int]
两者均已定义)。
Example:
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
元素和no Length
defined。我不确定如何解决这个问题,但伪代码看起来像:
implicit def foldSizeOfFixed[T[_] : Foldable : Not[Length], A : FixedSizeOf] = // ...
The 'Not[Length]
',显然,这是这里的组成部分。
我所知道的部分解决方案
1)为低优先级隐式定义一个类并扩展它,如'object Predef extends LowPriorityImplicits
'。
最后一个隐式(foldSizeOfFixed()
) 可以在父类中定义,并将被子孙类中的替代项覆盖。
我对此选项不感兴趣,因为我希望最终能够支持递归使用SizeOf
,这将防止低优先级基类中的隐式依赖子类中的隐式(我的理解正确吗?编辑:错误!隐式查找在子类的上下文中工作,这是一个可行的解决方案!)
2)更粗略的方法是依赖Option[TypeClass]
(例如。,:Option[Length[List]]
。其中一些,我可以写一个大的隐式选择Foldable
and SizeOf
作为强制性和Length
and FixedSizeOf
作为可选,并且依赖后者(如果可用)。 (来源:here http://www.scala-lang.org/node/8773)
这里的两个问题是缺乏模块化以及当无法找到相关类型类实例时回退到运行时异常(这个示例可能可以与此解决方案一起使用,但这并不总是可能的)
编辑:这是我能够通过可选隐式获得的最好结果。还没有到:
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()
从早些时候开始,这仍然是必要的。
感谢您的任何帮助或观点:-)