Расширенные ограничения типов в 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]
,