I am using a Generic Mapper to map a Model from a DBModel in scala 2.11
it has a method defined as:
def fromModelToDBModel(m: T) : R
where T is the type of the Model and R is the type of the DBModel.
This method is implemented the same way in almost all inheriting objects, ie:
override def fromModelToDBModel(p: RawModel): RawDBModelV1 = {
val values = RawModel.unapply(p).get
val makeDBModel = (RawDBModelV1.apply _).tupled
makeDBModel(values)
}
Is it possible to somehow define a generic object in the base Trait, so I can call apply/unapply on it?
example of the logic I would like to implement:
def fromModelToDBModel(m: T) : R = {
val values = Object[T].unapply(p).get
val makeDBModel = (Object[R].apply _).tupled
makeDBModel(values)
}
This would eliminate the need for writing every mapper individually, making the code more DRY.
You can look into generic programming with Shapeless.
With Shapeless, your function could be written as:
import shapeless._
def fromModelToDBModel[In, Out, Repr <: HList](p: In)(implicit genI: Generic.Aux[In, Repr], genO: Generic.Aux[Out, Repr]): Out = {
val values = genI.to(p)
val makeDBModel = genO.from _
makeDBModel(values)
}
case class RawModel(a: Int, b: String, c: Boolean)
case class RawModelV1(x: Int, y: String, z: Boolean)
val rawModel = RawModel(42, "foo", true)
val rawModelV1 = fromModelToDBModel[RawModel, RawModelV1, Int :: String :: Boolean :: HNil](RawModel(42, "foo", true))
This can be a little unwieldy with the required explicit type params so might want to refer to this SO question for ways to avoid explicit type params. For example, with partial application:
def fromModelToDBModel2[B] = new PartiallyApplied[B]
class PartiallyApplied[B] {
def apply[A, Repr](a: A)(implicit genA: Generic.Aux[A, Repr], genB: Generic.Aux[B, Repr]) = genB.from(genA.to(a))
}
val rawModelV1_2 = fromModelToDBModel2[RawModelV1](rawModel)
Related
I'm trying to implement a convenient generic field accessor based on LabelledGeneric.
The usage should look like:
case class Foo(aha: String, uhu: Double, ehe: Int)
case class Bar(uhu: Double, ahu: Boolean)
val foo: Foo = ???
val bar: Bar = ???
val uhuGenField = new GenField('uhu)
val uhuFooAccess = uhuGenField.from[Foo]
val uhuBarAccess = uhuGenField.from[Bar]
def someFunWithUhu[X](xs: Seq[X], access: uhuGenField.Access[X]) = ???
I spent some time trying to figure out how to achieve such behaviour.
Eventually I came up with this approach:
import shapeless._
import shapeless.ops.record.Selector
final class GenField[V](val fieldName: Symbol) {
val fieldWitness = Witness(fieldName)
type FieldNameType = fieldWitness.T
trait Access[C] {
def get(c: C): V
}
def from[C](implicit lg2hl: LGtoHL[C]): Access[C] = new Access[C] {
override def get(c: C): V = {
val labelledGeneric = lg2hl.labelledGeneric
val selector = Selector.mkSelector[labelledGeneric.Repr, FieldNameType, V]
selector(labelledGeneric.to(c))
}
}
}
// I need something like this to enable syntax like
// genField.from[DesiredClass]
// i.e. to "latch" Repr inside a single instance
// and to don't pass it explicitly to `from` method.
sealed trait LGtoHL[A] {
type Repr <: HList
val labelledGeneric: LabelledGeneric.Aux[A, Repr]
}
object LGtoHL {
implicit def mkLGtoHL[A, ARepr <: HList](implicit lg: LabelledGeneric.Aux[A, ARepr]): LGtoHL[A] = {
new LGtoHL[A] {
override type Repr = ARepr
override val labelledGeneric: LabelledGeneric.Aux[A, Repr] = lg
}
}
}
From my prospective this solution should be OK, but it still doesn't work.
The compilation fails with the following error message:
Error:(17, 41) lg2hl.Repr is not an HList type
val selector = Selector.mkSelector[labelledGeneric.Repr, FieldNameType, V]
Why does it complain lg2hl.Repr is not an HList type?
Repr is explicitly defined in LGtoHL as type Repr <: HList.
What is wrong with my code?
Very appreciate your help.
Why are lenses not enough?
import shapeless.{Lens, lens}
case class Foo(aha: String, uhu: Double, ehe: Int)
case class Bar(uhu: Double, ahu: Boolean)
val foo: Foo = Foo("a", 1.0, 2)
val bar: Bar = Bar(3.0, true)
val fooUhu: Lens[Foo, Double] = lens[Foo] >> 'uhu
val barUhu: Lens[Bar, Double] = lens[Bar] >> 'uhu
fooUhu.get(foo) // 1.0
barUhu.get(bar) // 3.0
The error message
lg2hl.Repr is not an HList type
comes from here: https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/generic.scala#L511
u.baseType(HConsSym) is now NoType.
I guess GenField[V](val fieldName: Symbol) will not work since fieldName in Witness(fieldName) must be known at compile time. For example
lens[Foo] >> 'uhu
works but
val uhu: Witness.`'uhu`.T = 'uhu.narrow
lens[Foo] >> uhu
doesn't. This is the reason why lenses, Witness, LabelledGeneric are implemented via macros.
I am currently trying to write a method that takes a JSON (what API does not matter here) and validates it. I want the method to look something like this:
def validateJson(json, expectedType: Map[String, Type(?)], allowedVals: Map[String, Seq[expectedType(key)]]): Boolean
The problem is: I do have a method jsonfield.validate[expectedType] but I do not know how to pass an unknown number of useable type parameters associated with strings to a method.
I'd gladly use some runtime reflection if that is possible here, or any advanced feature necessary to make this work easily. Any suggestions appreciated.
PS: I am using Play Framework 2.6.3
Edit:
I am trying to use the passed types like this
val allowed = allowedVals(field) // a Set
// if field contents contained in allowed value set...
if( allowed(field.validate[expectedType(field)].get) ) foo
Maybe you can use varargs in runtime or abstract over arity in compile time or just use an HList:
def foo[L <: HList](l: L) = ???
trait A
trait B
trait C
val a: A = new A {}
val b: B = new B {}
val c: C = new C {}
foo[A :: B :: C :: HNil](a :: b :: c :: HNil)
Sounds like you're looking for dependent type/dependent function/polymorphic function:
import shapeless.Poly1
import shapeless.syntax.singleton._
object expectedTypeAndValue extends Poly1 {
implicit val aCase: Case.Aux["a", Int] = at["a"](_ => 1)
implicit val bCase: Case.Aux["b", Long] = at["b"](_ => 2L)
implicit val cCase: Case.Aux["c", Double] = at["c"](_ => 3.0)
}
def validateJson(json: Json): Boolean = {
val x: Long = expectedTypeAndValue["b"]("b".narrow)
???
}
in Typelevel Scala or
import shapeless.{Poly1, Witness}
import shapeless.syntax.singleton._
object expectedTypeAndValue extends Poly1 {
implicit val aCase: Case.Aux[Witness.`"a"`.T, Int] = at[Witness.`"a"`.T](_ => 1)
implicit val bCase: Case.Aux[Witness.`"b"`.T, Long] = at[Witness.`"b"`.T](_ => 2L)
implicit val cCase: Case.Aux[Witness.`"c"`.T, Double] = at[Witness.`"c"`.T](_ => 3.0)
}
def validateJson(json: Json): Boolean = {
val x: Long = expectedTypeAndValue[Witness.`"b"`.T]("b".narrow)
???
}
in Lightbend Scala (ordinary Scala).
You can create also custom type class:
trait ExpectedTypeAndVals[S <: String] {
type Out
def apply(s: S): Set[Out]
}
object ExpectedTypeAndVals {
type Aux[S <: String, Out0] = ExpectedTypeAndVals[S] {type Out = Out0}
implicit def mkExpectedTypeAndVals[S <: String]: ExpectedTypeAndVals.Aux[S, ???] =
new ExpectedTypeAndVals[S] {
override type Out = ???
override def apply(s: S): Set[Out] = ???
}
}
def allowed[S <: String, Out](json: Json)(implicit
typeAndVals: ExpectedTypeAndVals.Aux[S, Out]
): Boolean = {
val str: S = ???
val set: Set[Out] = typeAndVals(str)
???
}
if(allowed(json)) {
???
}
Given this case class case class Location(id: BigInt, lat: Double, lng: Double)
and a list of strings List("87222", "42.9912987", "-93.9557953")
I would like to do something like Location.fromString(listOfString) in a way Location instance is created with string types converted into appropriate types.
Only way I can think of is define fromString method in each case class but I'm looking for a more generic solution each class can inherit. For example, I would have case class Location(...) extends Record, where Record implements fromString that does conversion based on argument types defined in Location class.
Normally for best performance in such you need to create some macro.
Luckily there is beautiful shapeless library with which you could create such generic reader with near-macro performance in no time using it's generic case class representation
First define typeclass and some instances for reading your fields:
trait Read[T] {
def fromString(s: String): T
}
implicit object readBigInt extends Read[BigInt] {
def fromString(s: String): BigInt = BigInt(s)
}
implicit object readDouble extends Read[Double] {
def fromString(s: String): Double = s.toDouble
}
Next define your main typeclass:
trait ReadSeq[T] {
def fromStrings(ss: Seq[String]): T
}
Now it's shapeless time (thinking about Dalí?) . We create reader for powerful Heterogenous List, which is almost like List but with of statically known length and element types.
It's no harder than to match simple List. Just define cases for empty list and cons:
import shapeless._
implicit object readHNil extends ReadSeq[HNil] {
def fromStrings(ss: Seq[String]) = HNil
}
implicit def readHList[X, XS <: HList](implicit head: Read[X], tail: ReadSeq[XS]) =
new ReadSeq[X :: XS] {
def fromStrings(ss: Seq[String]) = ss match {
case s +: rest => (head fromString s) :: (tail fromStrings rest)
}
}
Now we can use out-of-the-box macro mapping of HLists and case classes via Generic:
implicit def readCase[C, L <: HList](implicit gen: Generic.Aux[C, L], read: ReadSeq[L]) =
new ReadSeq[C] {
def fromStrings(ss: Seq[String]) = gen.from(read.fromStrings(ss))
}
Finally we could build our typeclass user:
def fromStringSeq[T](ss: Seq[String])(implicit read: ReadSeq[T]) = read.fromStrings(ss)
from this point having
case class Location(id: BigInt, lat: Double, lng: Double)
val repr = List("87222", "42.9912987", "-93.9557953")
you can ensure that
fromStringSeq[Location](repr) == Location(BigInt("87222"), 42.9912987, 93.9557953)
In Scala, if you create a typeclass, say the algebraic structure Monoid[T], you can provide many default typeclass implementations for different types that are monoids.
Suppose a monoid is defined as:
trait Monoid[T] {
def op(x: T, y: T): T
def id: T
}
Since Strings under the concatenation operation form a monoid, we can provide a default monoid for Strings like this:
implicit object StringMonoid extends Monoid[String] {
override def op(a: String, b: String): String = a + b
override def id: String = ""
}
This is rather easy, since String is not a generic type.
What I am asking for is how to provide a default monoid for Seq[T]s, in which the type parameter prevents me from creating an implicit object like I did above.
I could do:
class SeqMonoid[T] extends Monoid[Seq[T]] {
override def op(a: Seq[T], b: Seq[T]): Seq[T] = a ++ b
override def id: Seq[T] = Nil
}
implicit object intSeqMonoid extends SeqMonoid[Int]
implicit object doubleSeqMonoid extends SeqMonoid[Double]
implicit object stringSeqMonoid extends SeqMonoid[String]
...
But this approach doesn't utilize the beauty of generic types.
So, in general, my question is: Is there any way in Scala I can provide typeclass implementations for generic types?
You can provide an implicit function with the required type:
implicit def SeqMonoid[T]: Monoid[Seq[T]] = new Monoid[Seq[T]] {
override def op(a: Seq[T], b: Seq[T]): Seq[T] = a ++ b
override def id: Seq[T] = Nil
}
Variation without repeating Seq[T]:
object Monoid {
implicit def seqMonoid[T]:Monoid[Seq[T]] = {
type S = Seq[T]
new Monoid[S] {
def op(x: S, y: S) = x ++ y
def id = Nil
}
}
}
I'm trying to write a method in Scala that will take no arguments and will use a generic type to perform some logic in the method that will return output solely based on the generic type (similar to asInstanceOf[T] or isInstanceOf[T]).
It should be something like this:
val myObj = new MyClass
myObj.instanceOf[MyClass]
// returns true
This is what I thought may work.
class MyClass {
def instanceOf[Class[_]]: Bool = {
// ???
}
}
How do I implement this?
Thank you.
You could grab the type that was passed in by using ClassTags and use that.
A contrived example of what is asked in the title would be:
class Foo(name: String) {
def nameMatches[T: ClassTag]() =
classTag[T].runtimeClass.getName == name
}
new Foo("java.lang.String").nameMatches[String] //> res1: Boolean = true
new Foo("boolean").nameMatches[Boolean] //> res2: Boolean = true
This will work for the example you gave.
import scala.reflect.runtime.universe._
class MyClass {
def instanceOf[T: TypeTag] = typeOf[this.type] <:< typeOf[T]
}
Note that when you extend MyClass you will need to override instanceOf to get correct behaviour. Else you will get this:
scala> class MySubClass extends MyClass
defined class MySubClass
scala> (new MySubClass).instanceOf[MyClass] // works
res3: Boolean = true
scala> (new MySubClass).instanceOf[Any] // works
res4: Boolean = true
scala> (new MySubClass).instanceOf[MySubClass] // doesn't work
res5: Boolean = false
Another example of a generic method would be the standard library's implicitly, which you can trivially implement yourself:
def implicitly[T](implicit ev: T) = ev
so you can do things like look up type class instances:
trait Show[T] { def shows(t: T): String }
case class Person(name: String, age: Int)
implicit val personShow = new Show[Person] { def show(p: Person) = s"${p.name} # ${p.age} years" }
implicitly[Show[Person]]
this is useful in two cases:
you define a non-trivial type class instance using def (i.e. you generically "generate" type class instances from instances of other type classes) and you're not sure you got it right:
implicit def terriblyNonTrivialTCInstance[T, U, V, W, Ñ](implicit ev1: Foo, ev2: Bar, ev3: Baz, ...): FooTC[T, U] = ...
implicitly[FooTC[MyType1, MyType2]] // compile error if the above definition is badly constructed
your method takes an implicit evidence but instead of using an implicit arg list, you prefer to use a type bound, and later you'd like to grab an instance of the type class using implicitly:
def myMethod[T: FooTC[T, Int]](t: T) = {
val ev = implicitly[FooTC[T, Int]]
ev.doSmth(t)
}
instead of:
def myMehtod[T](t: T)(implicit ev: FooTC[T, Int]) = {
ev.doSmth(t)
}
P.S. in the stdlib, implicitly is implemented like this:
#inline def implicitly[T](implicit e: T) = e