Я сталкиваюсь с ошибкой о недостижимых implicits в области видимости:
Error:(38, 68) could not find implicit value for parameter strategy: XXX.NeoStrategy[T]
(summoner: Summoner, v: String) => summoner.summonEvaluation[T](v)
Я реализую ответ Тима на этот вопрос: https://stackoverflow.com/a/56668734/3896166
Я попытался импортировать implicit object Стратегии в рамках TypeTable с помощью:
import XXX.NeoStrategies._
но безуспешно.
Ниже приведены все файлы базовой логики, которые я хочу использовать:
object TypeLib {
sealed trait Type_top
trait Type_A extends Type_top
trait Type_B extends Type_top
}
trait NeoStrategy[T <: Type_top] {
def evaluate(v: String, helper: Helper): Int
}
object NeoStrategies {
implicit object NeoStrategy_A extends NeoStrategy[Type_A] {
def evaluate(v: String, helper: Helper): Int = 1
}
implicit object NeoStrategy_B extends NeoStrategy[Type_B] {
def evaluate(v: String, helper: Helper): Int = 2
}
}
case class Helper(name: String) {
def summonEvaluation[T <: Type_top](v: String)(implicit strategy: NeoStrategy[T]): Int = {
strategy.evaluate(v, this)
}
}
trait TypeOMap {
protected def computeStuff[T <: Type_top]: (Helper, String) => Int
protected val computeMap: Map[String, (Helper, String) => Int]
}
import XXX.NeoStrategies._
trait TypeTable extends TypeOMap {
override protected def computeStuff[T <: Type_top]: (Helper, String) => Int = {
(helper: Helper, v: String) => helper.summonEvaluation[T](v)
}
override protected val computeMap = Map(
"a" -> computeStuff[Type_A],
"b" -> computeStuff[Type_B]
)
}
class Summoner extends TypeTable {
def callsMapAndEvaluates(typeIdentifier: String, helper: Helper, param: String): Double = {
computeMap(typeIdentifier)(helper, param)
}
}
object StackO {
def main(args: Array[String]): Unit = {
val mySummoner = new Summoner
// mySummoner allows the selecting of a given type with
// its "typeIdentifier" input in combination with the "TypeTable" it extends
val r = mySummoner.callsMapAndEvaluates("a", Helper("make it right"), "I, parameter")
}
}
Это не первый раз, когда я использую implicits, но не с чем-то вроде computeMap выше. Тем не менее, я понимаю логику этого, но не могу сделать это правильно.
Как summoner.summonEvaluation[T](v) найти нужный implicit?
Ответ 1 · рейтинг 4 · Dmytro Mitin
Просто добавьте привязку к контексту
override protected def computeStuff[T <: Type_top : NeoStrategy] ...
Кажется, вы хотите работать с одноэлементными типами. В Scala 2.12 + Shapeless
import shapeless.Witness
object TypeLib {
sealed trait Type_top
trait Type_A extends Type_top
trait Type_B extends Type_top
}
import TypeLib._
trait NeoStrategy[S <: String] {
type T <: Type_top
def evaluate(v: S, summoner: Summoner): Int
}
object NeoStrategy {
type Aux[S <: String, T0 <: Type_top] = NeoStrategy[S] { type T = T0 }
def mkStrategy[S <: String, T0 <: Type_top](f: (S, Summoner) => Int): Aux[S, T0] = new NeoStrategy[S] {
override type T = T0
override def evaluate(v: S, summoner: Summoner): Int = f(v, summoner)
}
implicit val NeoStrategy_A: NeoStrategy.Aux[Witness.`"a"`.T, Type_A] = mkStrategy((_, _) => 1)
implicit val NeoStrategy_B: NeoStrategy.Aux[Witness.`"b"`.T, Type_B] = mkStrategy((_, _) => 2)
}
case class Summoner(name: String) {
def summonEvaluation[S <: String](s: Witness.Aux[S])(implicit
strategy: NeoStrategy[S]): Int = {
strategy.evaluate(s.value, this)
}
}
def main(args: Array[String]): Unit = {
val mySummoner = Summoner("stack question")
val r = mySummoner.summonEvaluation("a")
val r1 = mySummoner.summonEvaluation("b")
println(r) // 1
println(r1) // 2
}
В Скала 2.13
object TypeLib {
sealed trait Type_top
trait Type_A extends Type_top
trait Type_B extends Type_top
}
import TypeLib._
trait NeoStrategy[S <: String with Singleton] {
type T <: Type_top
def evaluate(v: S, summoner: Summoner): Int
}
object NeoStrategy {
type Aux[S <: String with Singleton, T0 <: Type_top] = NeoStrategy[S] { type T = T0 }
def mkStrategy[S <: String with Singleton, T0 <: Type_top](f: (S, Summoner) => Int): Aux[S, T0] = new NeoStrategy[S] {
override type T = T0
override def evaluate(v: S, summoner: Summoner): Int = f(v, summoner)
}
implicit val NeoStrategy_A: NeoStrategy.Aux["a", Type_A] = mkStrategy((_, _) => 1)
implicit val NeoStrategy_B: NeoStrategy.Aux["b", Type_B] = mkStrategy((_, _) => 2)
}
case class Summoner(name: String) {
def summonEvaluation[S <: String with Singleton](s: S)(implicit
value: ValueOf[S],
strategy: NeoStrategy[S]): Int = {
strategy.evaluate(s, this)
}
}
def main(args: Array[String]): Unit = {
val mySummoner = Summoner("stack question")
val r = mySummoner.summonEvaluation("a")
val r1 = mySummoner.summonEvaluation("b")
println(r) // 1
println(r1) // 2
}
Ответ 2 · рейтинг 1 · Astrid
Основная проблема заключается в следующем:
override protected def computeStuff[T <: Type_top]: (Helper, String) => Int = {
(helper: Helper, v: String) => helper.summonEvaluation[T](v) // implicit for NeoStrategy[T]...?
}
Поскольку summonEvaluation[T] требует неявного аргумента типа NeoStrategy[T], это означает, что вы должны иметь его в области действия для любого T, являющегося подклассом Type_top. Однако NeoStrategies предоставляет только два экземпляра: один для Type_A и Type_B. Этого недостаточно для компилятора. Понятное дело - например, вы не указали NeoStrategy для
Type_top себя
- подклассы
Type_A и Type_B (совершенно законно создавать)
Есть два основных способа справиться с этим:
Задержка неявного разрешения
В соответствии с другим ответом, вместо того, чтобы пытаться разрешить неявное внутри computeStuff, добавьте туда также привязку к контексту. Если точка, в которой вы должны указать неявное, достигается только тогда, когда вы знаете, что такое T, вам не нужно будет предоставлять экземпляры для любого возможного подтипа.
Предоставление имплицитов для всех возможных подтипов
Если вы абсолютно хотите сохранить неявное разрешение внутри computeStuff, вам придется предложить метод
implicit def getNeoStrategy[T <: Type_top] : NeoStrategy[T] = ???
К сожалению, выполнение этого, вероятно, потребует множества размышлений и возможных ошибок времени выполнения для пограничных случаев, поэтому я бы рекомендовал контекст, привязанный к computeStuff.