I have the following example with aux type, that does not compile:
trait Foo[A] {
type B
def value: B
}
object Foo {
type Aux[A0, B0] = Foo[A0] { type B = B0}
implicit def footInt = new Foo[Int] {
override type B = String
override def value = "Hey!"
}
implicit def fooString = new Foo[String] {
override type B = Boolean
override def value = true
}
}
import cats._
import cats.implicits._
object App {
def main(args: Array[String]): Unit = {
val x: Id[String] = "Hello"
println(foo(1))
println(foo("Hello"))
println(fooAux(1)(x))
}
def foo[T](t: T)(implicit f: Foo[T]): f.B = f.value
def fooAux[T, R] (t: T) (implicit f: Foo.Aux[T, R], id: Id[R]) : R = f.value
}
the compile complains:
Error:(15, 22) not enough arguments for method fooAux: (implicit f: com.sweetsoft.Foo.Aux[Int,R], implicit id: cats.Id[R])R.
Unspecified value parameter id.
println(fooAux(1)(x))
Error:(21, 55) parameter value id in method fooAux is never used
def fooAux[T, R] (t: T) (implicit f: Foo.Aux[T, R], id: Id[R]) : R = f.value
Error:(4, 23) Unused import
import cats.implicits._
What am I doing wrong?
It compiles with minor modifications:
trait Foo[A] {
type B
def value: B
}
object Foo {
type Aux[A0, B0] = Foo[A0] { type B = B0 }
implicit val footInt = new Foo[Int] {
override type B = String
override def value = "Hey!"
}
implicit def fooString = new Foo[String] {
override type B = Boolean
override def value = true
}
}
object App {
type Id[X] = X
def main(args: Array[String]): Unit = {
implicit val x: Id[String] = "Hello"
println(foo(1))
println(foo("Hello"))
println(fooAux(1))
}
def foo[T](t: T)(implicit f: Foo[T]): f.B = f.value
def fooAux[T, R] (t: T) (implicit f: Foo.Aux[T, R], id: Id[R]): R = id
}
The first error is pretty clear: the second argument list of fooAux needs two arguments, but you pass just a single x.
The second error message is also quite mundane: you don't ever use id.
The rest works almost as-is as soon as you provide an implicit String (I assume that you wanted to make x implicit).
Related
I'm trying to generate instances of case class using shapeless
This works for generating instances of Foo
case class Foo(x: Int, y: String)
class Context {
val random = new Random()
}
def genInt(context: Context): Int = {
context.random.nextInt()
}
def genString(context: Context): String = {
context.random.nextString(16)
}
object ClassesToGenerators extends Poly1 {
implicit def caseInt = at[Class[Int]](_ => genInt(_))
implicit def caseString = at[Class[String]](_ => genString(_))
}
val gen = Generic[Foo]
val context = new Context()
val classes = classOf[Int] :: classOf[String] :: HNil // can't figure out how to get this hlist programmatically
val generators = classes.map(ClassesToGenerators)
gen.from(generators.zipApply(generators.mapConst(context)))
However, I'm aiming to write something reusable like
def newInstance[T] -> T:
???
which could generate instances of any case classes that takes only int and string parameters.
As mentioned in the code snippet, I'm stuck at getting a hlist of case class attribute types i.e. would like to convert case class Foo(x: Int, y: String) to classOf[Int] :: classOf[String] :: HNil. Any other approaches to this problem are also very appreciated but I'm not looking for a generic way of generating random instances of cases classes (as my use-case is different and used random generator just as an example)
IMHO, Shapeless is better used when you forget about all the fancy stuff and just focus on simple typeclass derivation using HList like this:
import shapeless.{Generic, HList, HNil, :: => :!:}
import scala.util.Random
trait Context {
def random: Random
}
object Context {
object implicits {
implicit final val global: Context = new Context {
override final val random: Random = new Random()
}
}
}
trait Generator[A] {
def generate(context: Context): A
}
object Generator {
final def apply[A](implicit ev: Generator[A]): ev.type = ev
final def generate[A](implicit ev: Generator[A], ctx: Context): A =
ev.generate(ctx)
implicit final val IntGenerator: Generator[Int] =
new Generator[Int] {
override def generate(context: Context): Int =
context.random.nextInt()
}
implicit final val StringGenerator: Generator[String] =
new Generator[String] {
override def generate(context: Context): String =
context.random.nextString(16)
}
implicit final def auto[P <: Product](implicit ev: GeneratorGen[P]): Generator[P] = ev
}
sealed trait GeneratorRepr[R <: HList] extends Generator[R]
object GeneratorRepr {
implicit final val HNilGeneratorRepr: GeneratorRepr[HNil] =
new GeneratorRepr[HNil] {
override def generate(context: Context): HNil =
HNil
}
implicit final def HConsGeneratorRepr[E, T <: HList](
implicit ev: Generator[E], tail: GeneratorRepr[T]
): GeneratorRepr[E :!: T] =
new GeneratorRepr[E :!: T] {
override def generate(context: Context): E :!: T =
ev.generate(context) :: tail.generate(context)
}
}
sealed trait GeneratorGen[P <: Product] extends Generator[P]
object GeneratorGen {
implicit final def instance[P <: Product, R <: HList](
implicit gen: Generic.Aux[P, R], ev: GeneratorRepr[R]
): GeneratorGen[P] = new GeneratorGen[P] {
override def generate(context: Context): P =
gen.from(ev.generate(context))
}
}
Which can be used like this:
import Context.implicits.global
final case class Foo(x: Int, y: String)
val result = Generator.generate[Foo]
// result: Foo = Foo(-2127375055, "鞰Ϗƨ沺㗝䚮Ⴍ욏ꖱꬮӝ闉믃雦峷")
You can see the code running here.
Using built-in Shapeless type classes you can do
import shapeless.ops.hlist.FillWith
import shapeless.{Generic, HList, Poly0}
val context = new Context()
object ClassesToGenerators extends Poly0 {
implicit val caseInt = at[Int](genInt(context))
implicit val caseString = at[String](genString(context))
}
def newInstance[A] = new PartiallyApplied[A]
class PartiallyApplied[A] {
def apply[L <: HList]()(implicit
generic: Generic.Aux[A, L],
fillWith: FillWith[ClassesToGenerators.type, L]
): A = generic.from(fillWith())
}
newInstance[Foo]() // Foo(2018031886,⮐掐禃惌ᰧ佨妞ዤࠒ훿柲籐妭蝱⻤)
It is a common practice to provide a helper value class for accessing type classes - something like
object Show {
def apply[A](implicit sh: Show[A]): Show[A] = sh
def show[A: Show](a: A) = Show[A].show(a)
implicit class ShowOps[A: Show](a: A) {
def show = Show[A].show(a)
}
implicit val intCanShow: Show[Int] =
new Show[Int] {
def show(int: Int): String = s"int $int"
}
}
In my case, I have a type class with 2 parameters. And I cannot get the value class to work (MapperOps). I keep getting "could not find implicit value for parameter mapper"
trait Mapper[T, D] {
def toDto(i: T): D
}
object Mapper {
def map[T, D](i: T)(implicit mapper: Mapper[T, D]): D = implicitly[Mapper[T, D]].toDto(i)
def apply[T, D](implicit mapper: Mapper[T, D]): Mapper[T, D] = mapper
implicit def optionMapper[T, D](implicit mapper: Mapper[T, D]): Mapper[Option[T], Option[D]] = {
new Mapper[Option[T], Option[D]] {
override def toDto(i: Option[T]): Option[D] = i.map(mapper.toDto)
}
}
implicit def seqMapper[T, D](implicit mapper: Mapper[T, D]): Mapper[Seq[T], Seq[D]] = {
new Mapper[Seq[T], Seq[D]] {
override def toDto(i: Seq[T]): Seq[D] = i.map(mapper.toDto)
}
}
// Neither works
implicit class MapperOps1[T,D](a: T) {
def toDto = Mapper[T,D].toDto(a)
}
implicit class MapperOps2[T,D](a: T) {
def toDto(implicit mapper: Mapper[T,D]) = Mapper[T,D].toDto(a)
}
implicit class MapperOps3[T,D](a: T) {
def toDto[D](implicit mapper: Mapper[T,D]): D Mapper[T,D].toDto(a)
}
}
Notice the important difference that in
implicit class ShowOps[A: Show](a: A) { ... }
you have this A : Show part, which essentially desugares into
implicit class ShowOps[A](a: A)(implicit s: Show[A]) { ... }
Since there is no neat [T : MyTypeClass]-syntax for two-parameter "Type-Pair-Classes", you have to provide the implicit Mapper as a separate
parameter to the constructor:
implicit class MapperOps1[T, D](a: T)(implicit m: Mapper[T, D]) {
def toDto = Mapper[T, D].toDto(a)
}
The following little test compiles and outputs "42":
implicit object IntToStringMapper extends Mapper[Int, String] {
def toDto(i: Int): String = i.toString
}
import Mapper._
val s: String = 42.toDto
println(s)
Alternatively, you could try it with an implicit conversion (compiler will whine at you if you don't enable this feature explicitly, and users will whine at you if you don't use this feature wisely):
class MapperOps1[T,D](a: T, mapperTD: Mapper[T, D]) {
def toDto = {
implicit val m: Mapper[T, D] = mapperTD
Mapper[T,D].toDto(a)
}
}
import scala.language.implicitConversions
implicit def wrapIntoMapperOps1[T, D]
(a: T)
(implicit m: Mapper[T, D]): MapperOps1[T, D] = new MapperOps1(a, m)
I won't comment on your two other attempts: apparently, the compiler cannot instantiate those, because it doesn't get enough information about the type parameters before it has to instantiate a wrapper.
I don't know how to solve a problem in scala. Maybe someone can help me!
I have a case class (Operation) with some type parameter, this class can be returned by a method that know nothing about the parameter types (example a parser from string/json/xml).
So I need a way to transform from ShadowedOperation to Operation in some way, because the need is to parse from some data a ShadowedOperation and from this extract the typed version (an Operation).
I've write a code that should express the problem, it's simplified and try to do something different, but if this can be solved I can solve also the real need.
Probably with shapeless there is a solution, but I need to find a solution without it.
object box {
trait Transform[A, B] {
def apply(in: A): B
}
object Transform {
def instance[A, B](f: A => B): Transform[A, B] = new Transform[A, B] {
override def apply(in: A): B = f(in)
}
}
implicit class TransformOps[T](w: T) {
def transform(implicit t: Transform[T, String]) = t(w)
}
trait ShadowedOperation {
type I
type O
def param: String
def otherParam: Int
def in: I
def out: O
}
object ShadowedOperation {
// How can i do this in a generic, typed and wonderful way ???
implicit def operationToString: Transform[ShadowedOperation, String] = ???
}
case class Operation[I0, O0](
param: String,
otherParam: Int,
in: I0,
out: O0
) extends ShadowedOperation {type I = I0; type O = O0}
object Operation {
implicit def operationToString[I, O](
implicit
iToString: Transform[I, String],
oToString: Transform[O, String]
): Transform[Operation[I, O], String] =
Transform.instance(in => s"${in.otherParam} - ${in.param} - ${iToString(in.in)} - ${oToString(in.out)}")
}
def fakeParseFromString(in: String): List[ShadowedOperation] = {
// this simulate a parsing (or read from db) from string to extract the case class
List(Operation("param", 0, "in!", "out!"), Operation("param", 0, "in!", 100))
}
}
object Main extends App {
import box._
implicit val intToString: Transform[Int, String] = Transform.instance(_.toString)
implicit val stringToString: Transform[String, String] = Transform.instance(_.toString)
val op = Operation("param", 0, "in!", "out!")
val shadowedOperationList = fakeParseFromString("imagine that this string contain a json")
val opString = op.transform
val shadowedOpString = shadowedOperationList.map(_.transform)
println(opString)
println(shadowedOpString)
}
Thanks in advance to all who can help!
I made several changes:
added covariance/contravariance to Transform[-A, +B]
introduced type ShadowedOperation.Aux[I0, O0]
fixed returning type of fakeParseFromString using Aux-type
lifted operationToString from companion object of case class to companion object of trait with corresponding changes
imported instance: import op._
The whole code:
object box {
trait Transform[-A, +B] {
def apply(in: A): B
}
object Transform {
def instance[A, B](f: A => B): Transform[A, B] = new Transform[A, B] {
override def apply(in: A): B = f(in)
}
}
implicit class TransformOps[T](w: T) {
def transform(implicit t: Transform[T, String]) = t(w)
}
trait ShadowedOperation {
type I
type O
def param: String
def otherParam: Int
def in: I
def out: O
implicit def operationToString(
implicit
iToString: Transform[I, String],
oToString: Transform[O, String]
): Transform[ShadowedOperation.Aux[I, O], String] =
Transform.instance(in => s"${in.otherParam} - ${in.param} - ${iToString(in.in)} - ${oToString(in.out)}")
}
object ShadowedOperation {
type Aux[I0, O0] = ShadowedOperation { type I = I0; type O = O0 }
}
case class Operation[I0, O0](
param: String,
otherParam: Int,
in: I0,
out: O0
) extends ShadowedOperation {type I = I0; type O = O0}
def fakeParseFromString[I, O](in: Operation[I, O]): ShadowedOperation.Aux[I, O] = in
}
def main(args: Array[String]): Unit = {
import box._
implicit val intToString: Transform[Int, String] = Transform.instance(_.toString)
implicit val stringToString: Transform[String, String] = Transform.instance(_.toString)
val op = Operation("param", 0, "in!", "out!")
val shadowedOperation = fakeParseFromString(op)
import op._
val opString = op.transform
val shadowedOpString = shadowedOperation.transform
println(opString)//0 - param - in! - out!
println(shadowedOpString)//0 - param - in! - out!
}
So shapeless isn't necessary here.
When you write just ShadowedOperation instead of ShadowedOperation.Aux[???, ???] you loose some information about types. You have to find a way to restore this information about I, O (some casting, specifying types explicitly, defining more implicits etc.). Otherwise implicits won't work.
For instance in your updated example you can write
def fakeParseFromString(in: String): List[ShadowedOperation.Aux[String, Any]] =
List(Operation("param", 0, "in!","out!"), Operation("param", 0, "in!", 100))
implicit val anyToString: Transform[Any, String] = Transform.instance(_.toString)
val shadowedOpString = shadowedOperationList.map(_.transform)
println(shadowedOpString)
// List(Operation(param,0,in!,out!), Operation(param,0,in!,100))
I have the following trait:
trait CSVRowParser[A] {
def parse(row: Seq[String]): Try[A]
}
object CSVRowParser {
implicit def all[A, H <: HList](implicit gen: Generic.Aux[A, H],
read: CSVRowReader[H]): CSVRowParser[A] = new CSVRowParser[A] {
def parse(row: Seq[String]): Try[A] = {
read.from(row).map(gen.from)
}
}
def apply[A](implicit ev: CSVRowParser[A]): CSVRowParser[A] = ev
}
I have another class called CSVReader:
class CSVReader[A: CSVRowParser] {
def parse(path: String): ReaderWithFile[A] = ReaderWithFile[A](path)
case class ReaderWithFile[B: CSVRowParser](path: String) {
...
// how can I here identify the type of B?
}
}
I then do the call like this:
def apply[A: CSVRowParser] = new CSVReader[A]
val reader = apply[Address]
val withCustomConfig: Seq[Address] = reader parse "/csv-parser/address.csv" using CSVParserConfig(Pipe)
How can I get the runtime type of A inside the ReaderWithFile case class?
The problem is simple, I have an object which does a binary operation with two parameters. I want to only add fuels that have the same type, like this:
object Fuels {
case class Fuel[F <: FuelType](amount: Double, fuelType: F = Petrol) {
def +(that : Fuel[F]) = {
copy(amount = this.amount + that.amount)
}
}
def add[F <: FuelType](x: Fuel[F], y: Fuel[F]): Fuel[F] = x + y
sealed trait FuelType {
val name : String
}
case object Petrol extends FuelType{
override val name = "Petrol"
}
case object Diesel extends FuelType{
override val name = "Diesel"
}
case object Hydrogen extends FuelType{
override val name = "Hydrogen"
}
implicit def fuelMonoid[F <:FuelType](implicit fuelType: F) = new Monoid[Fuel]{
override def zero: Fuel[F] = Fuel(0, fuelType)
override def append(m1: Fuel[F], m2: Fuel[F]) : Fuel[F] = m1 + m2
}
}
Use it:
> Fuel(10, Petrol) + Fuel(20, Petrol)
> add(Fuel(10, Petrol), Fuel(10, Petrol))
Compilation error:
Expression of Type Fuels.Fuel[Nothing] does not conform to Fuels.Fuel[F]
The main issue is that both add and fuelMonoid fail to identify that we are dealing with items of the same type. The compiler can't resolve the type constraint, and infers Nothing.
For completion, here's Monoid, nothing extraordinary:
trait Monoid[A] {
def zero: A
def append(a1: A, a2: A): A
}
I changed type to Monoid[Fuel[F]], specified return type of implicit def and Fuel#+ and it works:
object Fuels {
trait Monoid[F] {
def zero: F
def append(f1: F, f2: F): F
}
object Monoid {
def fold[F](as: Seq[F], m: Monoid[F]): F = as.foldLeft(m.zero)(m.append)
}
case class Fuel[F <: FuelType](amount: Double, fuelType: F = Petrol) {
def +(that : Fuel[F]): Fuel[F] = {
copy(amount = this.amount + that.amount)
}
}
def add[F <: FuelType](x: Fuel[F], y: Fuel[F]): Fuel[F] = x + y
sealed trait FuelType {
val name : String
}
case object Petrol extends FuelType{
override val name = "Petrol"
}
case object Diesel extends FuelType{
override val name = "Diesel"
}
case object Hydrogen extends FuelType{
override val name = "Hydrogen"
}
implicit def fuelMonoid[F <:FuelType](implicit fuelType: F): Monoid[Fuel[F]] = new Monoid[Fuel[F]] {
override def zero: Fuel[F] = Fuel(0, fuelType)
override def append(m1: Fuel[F], m2: Fuel[F]): Fuel[F] = m1 + m2
}
}
object Main {
def main (args: Array[String] ) {
import Fuels._
println(Fuel(10, Petrol) + Fuel(20, Petrol))
println(add(Fuel(10, Petrol), Fuel(20, Petrol)))
println(Monoid.fold(Seq(Fuel(10, Petrol), Fuel(20, Petrol), Fuel(30, Petrol)), fuelMonoid(Petrol)))
}
}
http://ideone.com/kRocck
Upd1. But here is more interesting example: http://ideone.com/QKuCad. As you see, to make it work correctly I had to define the implicit value of a specified type (line 44). Is there any way to make this procedure more automated? (I mean, is there any way to make fuelMonoid acceptable as an implicit of any concrete FuelType subtype?)
Upd2. Yes, in fact there is: http://ideone.com/UEaFRj.