Использование границ контекста «отрицательно», чтобы гарантировать, что экземпляр класса типа отсутствует в области видимости

ТЛ; др: Как мне сделать что-то вроде приведенного ниже кода:

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) и для элементов, где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 а также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 <- 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() от ранее, что все еще необходимо.

Спасибо за любую помощь или перспективу :-)

Ответы на вопрос(1)

Ваш ответ на вопрос