Расширенные ограничения типов в Scala - логические операторы и неявные параметры

У меня есть следующий код, который работает хорошо.

package com.andrew

object ExperimentWithTypeConstraints {

  def union[T](t: T)(implicit c: (T =:= String)) = t match {
    case s: String => println(s"Some nice string: $s")
  }

  def main(args: Array[String]): Unit = {
    union("Hello.")
  }
}

Выход:

Some nice string: Hello.

Я хотел бы изменить определение метода union что-то вроде этого:

   def union[T](t: T)(implicit c: (T =:= String) Or (T =:= Int)) = t match {
    case s: String => println(s"Some nice string: $s")
    case i: Int => println(s"Some int: $i")
  }

Выход для union(1) должно быть следующее: Some int: 1

К сожалению, Scala не знает логического оператора Or (And, Not, ..) для таких случаев и, следовательно, его невозможно скомпилировать. Как мне это сделать?

Я нашел одно решение по следующему адресу ( http://hacking-scala.org/post/73854628325/advanced-type-constraints-with-type-classes), но, к сожалению, я плохо понимаю его. Можете ли вы сказать мне, как решить эту проблему на основе вашего подхода? Или вы можете объяснить решение из вышеупомянутого URL? Их решение работает, и это следующее:

@implicitNotFound("Argument does not satisfy constraints: ${A} Or ${B}")
trait Or[A, B]

object Or {
  private val evidence: Or[Any, Any] = new Object with Or[Any, Any]

  implicit def aExistsEv[A, B](implicit a: A) =
    evidence.asInstanceOf[Or[A, B]]

  implicit def bExistsEv[A, B](implicit b: B) =
    evidence.asInstanceOf[Or[A, B]]
}

Я не понимаю часть с Or, Or это объект. Как я могу совместить эту часть (T =:= String) Or (T =:= Int) с помощью Or все вместе?

Большое спасибо, Андрей

2 ответа

К сожалению, Scala не знает логического оператора Or (And, Not, ..) для таких случаев и, следовательно, его невозможно скомпилировать. Как мне это сделать?

Вот другой подход к той же проблеме. По общему признанию, трудно обернуть вашу голову, но это работает довольно хорошо.

trait Contra[-C]
type Union[A,B] = {
  type Check[Z] = Contra[Contra[Z]] <:< Contra[Contra[A] with Contra[B]]
}

Использование:

def f[T: Union[String,Int]#Check](arg:T) = arg match {
  case s:String         => s"got string: ${s.toUpperCase}"
  case i:Int if i < 100 => s"got small Int: $i"
  case i:Int            => s"got bigger Int: $i"
}

Подтверждение концепции:

f(119)            //res0: String = got bigger Int: 119
f("string time")  //res1: String = got string: STRING TIME
f(true)           //does not compile

Линии

implicit def aExistsEv[A, B](implicit a: A) =
  evidence.asInstanceOf[Or[A, B]]

implicit def bExistsEv[A, B](implicit b: B) =
  evidence.asInstanceOf[Or[A, B]]

означает, что если у вас есть неявно A то у вас неявно есть Or[A, B] и аналогично, если у вас есть неявно B то у вас неявно есть Or[A, B],

Это именно то, как Or работает в логике: если A истинно, то A Or B истинно и аналогично, если B истинно, тогда A Or B истинно.

И, наконец, если T является String затем неявный T =:= String предоставляется, и если T является Int затем неявный T =:= Int предоставлен.

A X B такой же как X[A, B], так A Or B такой же как Or[A, B],

Другие вопросы по тегам