具有多个参数的类型类。如何召唤只有一个参数的实例?

Typeclass with multiple parameters. How to summon an instance having only one parameter?

我一直在尝试创建某种类型类,但遇到了隐式解析问题。 基本上我想生成随机数据并调整生成参数 - 数字间隔,数组长度和间隔等。 这是我现在得到的:

import scala.util.Random

trait PrimitiveGenerator[T <: AnyVal, Bounds] {

  def generate(bounds: Bounds): T

  def generatePossibly(bounds: Bounds): Option[T] = if (Random.nextDouble() < 0.5) None else Some(generate(bounds))

}

object PrimitiveGenerator {
  def apply[A <: AnyVal](implicit impl: PrimitiveGenerator[A, _]) = impl
}

object Generators {

  implicit object IntGenerator extends PrimitiveGenerator[Int, (Int, Int)] {
    override def generate(bounds: (Int, Int) = (0, 1)): Int = Random.nextInt((bounds._2 - bounds._1) + 1) + bounds._1
  }

}


object Test extends App {

  import Generators._
  PrimitiveGenerator[Int].generate((0, 1)) //error is here
}

在 Intellij Idea 中,这是失败的:

 found   : (Int, Int)
 required: _ where type _
  PrimitiveGenerator[Int].generate((0, 1))

我知道这里使用下划线是错误的,但我如何重写它以仅基于第一个类型参数 (A) 来调用 DataGenerator 的实例。从编译的角度来看,它似乎非常安全: 如果编译器找到 Int 的 DataGenerator,仅在一个示例中,它会立即使用它,如果它发现其中几个具有不同的 Bounds,则只是 returns 一个错误。我可能会解决这个错误,将这个参数添加到隐式解析中。那你怎么看?

编辑 1 感谢@Dmytro Mitin 解决了这个问题! 进一步看,我想为 Array 做一个实现,这样如果我们想为数组调用一个实例,我们应该有一个 Array 的参数类型的实例,就像这样:

import scala.reflect.ClassTag
import scala.util.Random

trait PrimitiveGenerator[T] {
  type Bounds
  def generate(bounds: Bounds): T
  def generatePossibly(bounds: Bounds): Option[T] = if (Random.nextDouble() < 0.5) None else Some(generate(bounds))
}

object PrimitiveGenerator {
  type Aux[T, Bounds0] = PrimitiveGenerator[T] { type Bounds = Bounds0 }
  def apply[A](implicit impl: PrimitiveGenerator[A]): Aux[A, impl.Bounds] = impl
}

object Generators {
  implicit object IntGenerator extends PrimitiveGenerator[Int] {
    override type Bounds = (Int, Int)
    override def generate(bounds: (Int, Int) = (0, 1)): Int = Random.nextInt((bounds._2 - bounds._1) + 1) + bounds._1
  }

  implicit def toGenericArrayGenerator[A](implicit generator: PrimitiveGenerator[A],
                                          classTag: ClassTag[A]): PrimitiveGenerator[Array[A]] = new PrimitiveGenerator[Array[A]] {
    override type Bounds = ((Int, Int), generator.Bounds) //It means generate array of length from n to m where elements comply to Bounds of base generator

    override def generate(bounds: Bounds): Array[A] = {
      Array[A]()
    }
  }
}

object Test extends App {
  import Generators._
  println(PrimitiveGenerator[Int].generate((0, 42)))
  PrimitiveGenerator[Array[Int]].generate((1 -> 10, 0 -> 42))
}

现在我正在尝试动态创建数组生成器,并且边界根据基本生成器边界(按计划)略有变化。 但是出了点问题,现在我有:

Error: type mismatch;
 found   : ((Int, Int), (Int, Int))
 required: impl.Bounds
  PrimitiveGenerator[Array[Int]].generate((1 -> 10, 0 -> 42))

如何解决?

例如尝试

object PrimitiveGenerator {
  def apply[A <: AnyVal] = new PartiallyApplied[A]

  class PartiallyApplied[A <: AnyVal] {
    def apply[B]()(implicit impl: PrimitiveGenerator[A, B]) = impl
  }
}    

object Test extends App {
  import Generators._
  PrimitiveGenerator[Int]().generate((0, 1))
}

object PrimitiveGenerator {
  def generate[A <: AnyVal, B](b: B)(implicit impl: PrimitiveGenerator[A, B]) = impl.generate(b)
}

object Test extends App { 
  import Generators._
  PrimitiveGenerator.generate((0, 1))
}

trait PrimitiveGenerator[T <: AnyVal] {
  type Bounds
  def generate(bounds: Bounds): T
  def generatePossibly(bounds: Bounds): Option[T] = if (Random.nextDouble() < 0.5) None else Some(generate(bounds))
}

object PrimitiveGenerator {
  type Aux[T <: AnyVal, Bounds0] = PrimitiveGenerator[T] { type Bounds = Bounds0 }
  def apply[A <: AnyVal](implicit impl: PrimitiveGenerator[A]): Aux[A, impl.Bounds] = impl
}

object Generators {    
  implicit object IntGenerator extends PrimitiveGenerator[Int] {
    override type Bounds = (Int, Int)
    override def generate(bounds: (Int, Int) = (0, 1)): Int = Random.nextInt((bounds._2 - bounds._1) + 1) + bounds._1
  }    
}

object Test extends App { 
  import Generators._
  PrimitiveGenerator[Int].generate((0, 1))
}

trait PrimitiveGenerator[T <: AnyVal] {
  type Bounds = (T, T)
  def generate(bounds: Bounds): T
  def generatePossibly(bounds: Bounds): Option[T] = if (Random.nextDouble() < 0.5) None else Some(generate(bounds))
}

object PrimitiveGenerator {
  def apply[A <: AnyVal](implicit impl: PrimitiveGenerator[A]): PrimitiveGenerator[A] = impl
}

object Generators {
  implicit object IntGenerator extends PrimitiveGenerator[Int] {
    override def generate(bounds: (Int, Int) = (0, 1)): Int = Random.nextInt((bounds._2 - bounds._1) + 1) + bounds._1
  }
}

object Test extends App {
  import Generators._
  PrimitiveGenerator[Int].generate((0, 1))
}