Импорт не приносит последствий в объеме - PullRequest
0 голосов
/ 26 июня 2019

Я сталкиваюсь с ошибкой о недоступности implicit s в области:

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")
  }
}

Это не первый раз, когда я использую implicit s, но не с чем-то вроде computeMap выше. Тем не менее, я понимаю логику этого, но не могу сделать это правильно.

Как мне summoner.summonEvaluation[T](v) найти требуемый implicit?

Ответы [ 2 ]

4 голосов
/ 26 июня 2019

Просто добавьте привязку к контексту

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
  }

В Scala 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
  }
1 голос
/ 27 июня 2019

Основная проблема заключается в следующем:

  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.

...