Использование границ контекста «отрицательно», чтобы гарантировать, что экземпляр класса типа отсутствует в области видимости
ТЛ; др: Как мне сделать что-то вроде приведенного ниже кода:
def notFunctor[M[_] : Not[Functor]](m: M[_]) = s"$m is not a functor"
''Not[Functor]
Будучи здесь вычурной частью.
Я хочу, чтобы это успешно, когда "м" при условии, что это не 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
) и для элементов, гдеFixedSizeOf
определяется, мы получаем улучшенную производительность.
В остальных случаях мы просматриваем коллекцию и суммируем индивидуальные размеры.
Моя проблема в тех случаях, когда обаLength
а такжеFoldable
определены для контейнера, иFixedSizeOf
определяется для элементов. Это очень распространенный случай (например,List[Int]
как определили).
Пример:
scala> implicitly[SizeOf[List[Int]]].sizeOf(List(1,2,3))
: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
а такжеFixedSizeOf
как необязательный, и полагается на последнее, если они доступны. (источник:Вот)
Здесь есть две проблемы: отсутствие модульности и возврат к исключениям времени выполнения, когда невозможно найти соответствующие экземпляры классов типов (этот пример, вероятно, может быть создан для работы с этим решением, но это 'не всегда возможно)
РЕДАКТИРОВАТЬ: Это лучшее, что я смог получить с дополнительными последствиями. Это'Там еще нет:
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