В соответствии с этим вопросом я пытаюсь найти способ заставить компилятор Scala вывести наибольший общий подтип двух типов А и В.
Что-то вроде «А без Б», где определение такое:
(A without B = C) === (A = C with B)
Или функция типа, которая возвращает C, где:
РЕДАКТИРОВАТЬ:
A <: C && C <:!< B
т.е. A является подтипом C, а C не является подтипом B
На самом деле я ожидаю, что кто-то укажет, что это не то же самое, что «самый большой общий подтип», поскольку мне на самом деле не требуется этот A <: B
.
Применение:
trait Syntax
trait ANYSYNTAX extends Syntax
trait NUMERIC extends ANYSYNTAX
trait DISCRETE extends ANYSYNTAX
trait POSITIVE extends ANYSYNTAX
trait CONST extends ANYSYNTAX
type NUMCONST = NUMERIC with CONST
type POSCONST = POSITIVE with CONST
type ORDINALCONST = DISCRETE with CONST
type INTEGER = NUMERIC with DISCRETE
type POSNUM = POSITIVE with NUMERIC
type POSINT = POSNUM with INTEGER
type INTCONST = INTEGER with NUMCONST with ORDINALCONST
type POSNUMCONST = POSNUM with POSCONST with NUMCONST
type POSINTCONST = POSNUMCONST with INTCONST with POSINT
Затем я хотел бы иметь возможность распространять ограничения типа следующим образом:
abstract class Expression[+R]( val args: Expression[_]* )
case class Add[A <: R, R <: NUMERIC]( arg1: Expression[A], arg2: Expression[A] ) extends Expression[R] {
case class Subtract[A <: R, R : A without POSITIVE]( arg1: Expression[A], arg2: Expression[A] ) extends Expression[R] {
case class Multiply[A <: R, R <: NUMERIC]( arg1: Expression[A], arg2: Expression[A] ) extends Expression[R]{
case class Divide[A <: R, R : A without DISCRETE]( arg1: Expression[A], arg2: Expression[A] ) extends Expression[R] {
Я пытался придумать что-то, используя некоторые ограничения типа, заимствованные из других ответов SO:
sealed class =!=[A,B]
trait LowerPriorityImplicits {
implicit def equal[A]: =!=[A, A] = sys.error("should not be called")
}
object =!= extends LowerPriorityImplicits {
implicit def nequal[A,B](implicit same: A =:= B = null): =!=[A,B] =
if (same != null) sys.error("should not be called explicitly with same type")
else new =!=[A,B]
}
// Encoding for "A is not a subtype of B"
trait <:!<[A, B]
// Uses ambiguity to rule out the cases we're trying to exclude
implicit def nsub[A, B] : A <:!< B = null
implicit def nsubAmbig1[A, B >: A] : A <:!< B = null
implicit def nsubAmbig2[A, B >: A] : A <:!< B = null
У меня есть несколько тестовых случаев:
implicitly[POSINT <:!< CONST]
implicitly[POSITIVE <:!< OPINION]
implicitly[DOGMA <:!< CONST]
implicitly[POSINTCONST <:< POSITIVE with CONST]
implicitly[POSINTCONST <:< POSCONST]
implicitly[POSITIVE with CONST <:!< POSINTCONST]
implicitly[POSITIVE =:= POSCONST without CONST]
implicitly[NUMERIC =:= INTEGER without DISCRETE]
implicitly[POSINT =:= POSINTCONST without CONST]
Они должны потерпеть неудачу:
implicitly[POSINT =:= POSINTCONST without OPINION]
implicitly[POSINT with OPINION =!= POSINTCONST without OPINION]
A <: B
, тоC
не существует, а иначеC
— это простоA
. - person Travis Brown   schedule 19.08.2013C: POSINT
,B: CONST
. ТогдаA: C with B
= POSINTCONST. Согласно моему первому определению,POSINTCONST without CONST =:= POSINT
. Если, с другой стороны,A <:!< B
, например.NUMCONST without POSITIVE
то я бы ожидалC:NUMCONST
как вы говорите. - person RealName   schedule 19.08.2013