tl;dr : 以下の構成されたコードのようなことを行うにはどうすればよいですか:
def notFunctor[M[_] : Not[Functor]](m: M[_]) = s"$m is not a functor"
「Not[Functor]
」は、ここで構成されている部分です。
提供された 'm' が Functor でない場合は成功し、それ以外の場合はコンパイラを失敗させたいです。
解決済み: 残りの質問をスキップして、すぐに下の回答に進んでください。
私が達成しようとしているのは、大まかに言えば「否定的な証拠」です。
擬似コードは次のようになります。
// 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
と、 a が定義されている要素の場合、FixedSizeOf
パフォーマンスが向上します。
残りのケースでは、コレクションを調べて個々のサイズを合計します。
私の問題は、 と の両方Length
がFoldable
コンテナーに対してFixedSizeOf
定義され、 が要素に対して定義されている場合です。これはここでは非常に一般的なケースです (例: List[Int]
has both defined)。
例:
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]
(例: . それらのいくつかと私は、andを必須およびオプションとして選択し、利用可能な場合は後者に依存するOption[Length[List]]
1 つの大きな古い暗黙的なものを書くことができます。 (ソース:ここで)Foldable
SizeOf
Length
FixedSizeOf
ここでの 2 つの問題は、モジュール性の欠如と、関連する型クラスのインスタンスが見つからない場合の実行時例外へのフォールバックです (この例は、おそらくこのソリューションで動作するように作成できますが、常に可能であるとは限りません)。
編集:これは、オプションの暗黙的なもので取得できた最高のものです。まだありません:
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()
これが以前から衝突することを除いて、これはまだ必要です。
助けや視点をありがとう:-)