Using cats.Contravariant typeclass - scala

I'm trying to apply my Contravariant typeclass with syntax and faced the issue that it is not found. Here is what I currently have:
import cats._
import cats.implicits._
object Test {
type Foo[A] = A => Unit
private val f: Foo[String] = (_: String) => ()
implicit val cvar: Contravariant[Foo] = null
private val FF: Foo[Int] = f.contramap((i: Int) => //error: value contramap is not a member of Foo
String.valueOf(i)
)
}
I don't understand it. I provided implicit Contravariant[Foo], but the syntax is not applied anyway. What's wrong?

The mistake was that I did not extend the ContravariantSyntax. Removing implicit and mixing in it works as expected:
import cats._
import cats.syntax.ContravariantSyntax
object Test extends ContravariantSyntax{
type Foo[A] = A => Unit
private val f: Foo[String] = (_: String) => ()
implicit val cvar: Contravariant[Foo] = null
private val FF: Foo[Int] = f.contramap((i: Int) => //compiles - Ok!
String.valueOf(i)
)
}

Related

Finding the second matching implicit

Consider the following setup:
trait Foo[A]
object Foo extends Priority2
trait Priority0 {
implicit def foo1: Foo[Int] = new Foo[Int] {}
}
trait Priority1 extends Priority0 {
implicit def foo2: Foo[Boolean] = new Foo[Boolean] {}
}
trait Priority2 extends Priority1 {
implicit def foo3: Foo[Double] = new Foo[Double] {}
}
Now, in a REPL (having loaded the above code up), I can do the following:
scala> def implicitlyFoo[A](implicit foo: Foo[A]) = foo
implicitlyFoo: [A](implicit foo: Foo[A])Foo[A]
scala> implicitlyFoo
res1: Foo[Double] = Priority2$$anon$3#79703b86
Is there a way to encode with some typelevel magic that I want to skip over the instances with A =:= Double, but still let type inference figure out what A is?
I do not want to shadow foo3. This is an MVCE: in my real case, foo3 is a def with other implicit arguments (and may play an indirect role in deriving other Foo's).
I've tried =:!= from shapeless but to no avail:
scala> import shapeless._
import shapeless._
scala> def implicitlyFoo2[A](implicit foo: Foo[A], ev: A =:!= Double) = foo
implicitlyFoo2: [A](implicit foo: Foo[A], implicit ev: A =:!= Double)Foo[A]
scala> implicitlyFoo2
<console>:16: error: ambiguous implicit values:
both method neqAmbig1 in package shapeless of type [A]=> A =:!= A
and method neqAmbig2 in package shapeless of type [A]=> A =:!= A
match expected type Double =:!= Double
implicitlyFoo2
^
Dirty hack is to downcast macro context to its implemenation and use compiler internals.
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
trait Foo[A] {
def say: String
}
trait Priority0 {
implicit def foo1: Foo[Int] = new Foo[Int] {
override def say: String = "int"
}
}
trait Priority1 extends Priority0 {
implicit def foo2: Foo[Boolean] = new Foo[Boolean] {
override def say: String = "bool"
}
}
trait Priority2 extends Priority1 {
implicit def foo3: Foo[Double] = new Foo[Double] {
override def say: String = "double"
}
}
object Foo extends Priority2
def materializeSecondFoo[A]: Foo[A] = macro impl
def impl(c: whitebox.Context): c.Tree = {
import c.universe._
val context = c.asInstanceOf[reflect.macros.runtime.Context]
val global: context.universe.type = context.universe
val analyzer: global.analyzer.type = global.analyzer
var infos = List[analyzer.ImplicitInfo]()
new analyzer.ImplicitSearch(
tree = EmptyTree.asInstanceOf[global.Tree],
pt = typeOf[Foo[_]].asInstanceOf[global.Type],
isView = false,
context0 = global.typer.context.makeImplicit(reportAmbiguousErrors = false),
pos0 = c.enclosingPosition.asInstanceOf[global.Position]
) {
override def searchImplicit(
implicitInfoss: List[List[analyzer.ImplicitInfo]],
isLocalToCallsite: Boolean
): analyzer.SearchResult = {
val implicitInfos = implicitInfoss.flatten
if (implicitInfos.nonEmpty) {
infos = implicitInfos
}
super.searchImplicit(implicitInfoss, isLocalToCallsite)
}
}.bestImplicit
val secondBest = infos.tail.head
global.gen.mkAttributedRef(secondBest.pre, secondBest.sym).asInstanceOf[Tree]
}
materializeSecondFoo.say // bool
Tested in 2.12.8. Motivated by shapeless.Cached.
In 2.13.0 materializeSecondFoo.say should be replaced with
val m = materializeSecondFoo
m.say
The latter is still working in 2.13.10.
Scala 3 implementation:
import scala.quoted.{Quotes, Type, Expr, quotes}
import dotty.tools.dotc.typer.{Implicits => dottyImplicits}
transparent inline def materializeSecondFoo: Foo[_] = ${impl}
def impl(using Quotes): Expr[Foo[_]] = {
import quotes.reflect.*
given c: dotty.tools.dotc.core.Contexts.Context =
quotes.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx
val typer = c.typer
val search = new typer.ImplicitSearch(
TypeRepr.of[Foo[_]].asInstanceOf[dotty.tools.dotc.core.Types.Type],
dotty.tools.dotc.ast.tpd.EmptyTree,
Position.ofMacroExpansion.asInstanceOf[dotty.tools.dotc.util.SourcePosition].span
)
def eligible(contextual: Boolean): List[dottyImplicits.Candidate] =
if contextual then
if c.gadt.isNarrowing then
dotty.tools.dotc.core.Contexts.withoutMode(dotty.tools.dotc.core.Mode.ImplicitsEnabled) {
c.implicits.uncachedEligible(search.wildProto)
}
else c.implicits.eligible(search.wildProto)
else search.implicitScope(search.wildProto).eligible
def implicits(contextual: Boolean): List[dottyImplicits.SearchResult] =
eligible(contextual).map(search.tryImplicit(_, contextual))
val contextualImplicits = implicits(true)
val nonContextualImplicits = implicits(false)
val contextualSymbols = contextualImplicits.map(_.tree.symbol)
val filteredNonContextual = nonContextualImplicits.filterNot(sr => contextualSymbols.contains(sr.tree.symbol))
val successes = (contextualImplicits ++ filteredNonContextual).collect {
case success: dottyImplicits.SearchSuccess => success.tree.asInstanceOf[ImplicitSearchSuccess].tree
}
successes.tail.head.asExprOf[Foo[_]]
}
materializeSecondFoo.say // bool
val foo = materializeSecondFoo
foo: Foo[Boolean] // compiles
Scala 3.2.0.

Scala, generic tuple

I have a generic method that can accept any tuple of any size, the only constraint is that the first element of this tuple should be of type MyClass.
Something like this:
trait MyTrait[T <: (MyClass, _*)] {
getMyClass(x: T): MyClass = x._1
}
I've tried this
trait MyTrait[T <: (MyClass, _) with (MyClass, _, _) with (MyClass, _, _) with ...] {
getMyClass(x: T): MyClass = x._1
}
but I get the error unboud wildcard type
If you want to do this without either boilerplate or runtime reflection, Shapeless is your best bet. You can use the IsComposite type class to put type-level constraints on the first element of a tuple:
import shapeless.ops.tuple.IsComposite
trait MustBeFirst
class MyClass[P <: Product](p: P)(implicit ev: IsComposite[P] { type H = MustBeFirst }) {
def getMustBeFirst(x: P): MustBeFirst = ev.head(p)
}
And then:
scala> val good2 = (new MustBeFirst {}, "")
good2: (MustBeFirst, String) = ($anon$1#7294acee,"")
scala> val good3 = (new MustBeFirst {}, "", 123)
good3: (MustBeFirst, String, Int) = ($anon$1#6eff9288,"",123)
scala> val good4 = (new MustBeFirst {}, "", 'xyz, 123)
good4: (MustBeFirst, String, Symbol, Int) = ($anon$1#108cdf99,"",'xyz,123)
scala> val bad2 = ("abc", 123)
bad2: (String, Int) = (abc,123)
scala> new MyClass(good2)
res0: MyClass[(MustBeFirst, String)] = MyClass#5297aa76
scala> new MyClass(good3)
res1: MyClass[(MustBeFirst, String, Int)] = MyClass#3f501844
scala> new MyClass(good4)
res2: MyClass[(MustBeFirst, String, Symbol, Int)] = MyClass#24e15478
scala> new MyClass(bad2)
<console>:15: error: could not find implicit value for parameter ev: shapeless.ops.tuple.IsComposite[(String, Int)]{type H = MustBeFirst}
new MyClass(bad2)
^
If you need to use a trait, you can put the ev (for "evidence") requirement inside the definition instead of in the constructor:
trait MyTrait[P <: Product] {
implicit def ev: IsComposite[P] { type H = MustBeFirst }
}
Now any class instantiating MyTrait will have to provide evidence that P is a tuple with MustBeFirst as its first element.
It's a little bit unsafe but you can use Structural type in this case:
trait MyTrait {
def getMyClass(x: {def _1: MyClass}): MyClass = x._1
}
Scala can't use generic tuple with unknown size because Products don's inherit themeselfs. You can try to use Shapeless or Products from play json lib.
This is now possible in Scala 3 and very straightforward:
class MyClass
trait MyTrait[T <: MyClass *: _] {
def getMyClass(x: T): MyClass = x.head
}
The *: infix operator is the type level equivalent of the +: sequence prepend (or :: for lists). So we essentially require type T to be a tuple such that its first member is of type MyClass. Note that the members of generic tuples cannot be retrieved using the usual _1, _2, ... attributes, but should be accessed using list-like methods (head, tail, apply, etc.). More surprising, these methods are type-safe since they carry precise type information.
Demo:
object Test1 extends MyTrait[(MyClass, Int, String)] // Compiles
//object Test2 extends MyTrait[(Int, String)] // Does not compile!
//object Test3 extends MyTrait[EmptyTuple] // Neither does this
val myClass = Test1.getMyClass((new MyClass, 1, "abc"))
summon[myClass.type <:< MyClass] // Compiles
Read more about match types, type inference.
You need to inherit your trait from Product, through which you can have productIterator, productArity and, productElement to handle the returned value. Here is an example
case class MyClass()
trait MyTrait[T <: Product] {
def getMyClass(x: T): Option[MyClass] =
if(
x.productIterator.hasNext
&&
x.productIterator.next().isInstanceOf[MyClass]
){
Some(x.productIterator.next().asInstanceOf[MyClass])
} else {
None
}
}
case class Test() extends MyTrait[Product]
And you can invoke like this
Test().getMyClass((MyClass(), 1,3,4,5))
//res1: Option[MyClass] = Some(MyClass())
Test().getMyClass((1,3,4,5))
//res2: Option[MyClass] = None
Hope this helps you.
If you are looking for compile time guarantee then this is one of the use cases for
Shapeless,
You need to add Shapeless in your build.sbt,
libraryDependencies ++= Seq("
com.chuusai" %% "shapeless" % "2.3.3"
)
Now, you can use Shapeless to define a typesafe getter which comes with compile time guarantees,
scala> import shapeless._
// import shapeless._
scala> import ops.tuple.IsComposite
// import ops.tuple.IsComposite
scala> import syntax.std.tuple._
// import syntax.std.tuple._
scala> case class Omg(omg: String)
// defined class Omg
scala> val myStringTuple = ("All is well", 42, "hope")
// myStringTuple: (String, Int, String) = (All is well,42,hope)
scala> val myOmgTuple = (Omg("All is well"), 42, "hope")
// myOmgTuple: (Omg, Int, String) = (Omg(All is well),42,hope)
Now if you want to enrich your tuples with a "first" getter with a specific type then,
scala> implicit class GetterForProduct[B <: Product](b: B) {
| def getFirst[A](implicit comp: IsComposite[B] { type H = A }): A = b.head
| }
// defined class GetterForProduct
scala> val myString = myStringTuple.getFirst[String]
// myString: String = All is well
scala> val myOmgError = myOmgTuple.getFirst[String]
// <console>:24: error: could not find implicit value for parameter comp: shapeless.ops.tuple.IsComposite[(Omg, Int, String)]{type H = String}
// val myOmgError = myOmgTuple.getFirst[String]
// ^
scala> val myOmg = myOmgTuple.getFirst[Omg]
// myOmg: Omg = Omg(All is well
If you don't need the implicit enrichment and are just looking for a way to "lock" the type in a getter and use it for corresponding types,
scala> trait FirstGetterInProduct[A] {
| def getFirst[B <: Product](b: B)(implicit comp: IsComposite[B] { type H = A }): A = b.head
| }
// defined trait FirstGetterInProduct
scala> object firstGetterInProductForString extends FirstGetterInProduct[String]
// defined object firstGetterInProductForString
scala> object firstGetterInProductForOmg extends FirstGetterInProduct[Omg]
// defined object firstGetterInProductForOmg
// Right tuple with right getter,
scala> val myString = firstGetterInProductForString.getFirst(myStringTuple)
// myString: String = All is well
// will fail at compile time for tuple with different type for first
scala> val myOmgError = firstGetterInProductForString.getFirst(myOmgTuple)
// <console>:23: error: could not find implicit value for parameter comp: shapeless.ops.tuple.IsComposite[(Omg, Int, String)]{type H = String}
// val myOmgError = firstGetterInProductForString.getFirst(myOmgTuple)
// ^
scala> val myOmg = firstGetterInProductForOmg.getFirst(myOmgTuple)
// myOmg: Omg = Omg(All is well)

Mapping of String to Type

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)) {
???
}

How to get constructor arguments in a method using typetags/mirrors?

For Case Class:
case class MyClass(param1: String, param2: String)
Why does this reflective method:
import scala.reflect.runtime.universe._
import scala.reflect.runtime.currentMirror
import scala.reflect.runtime.{ universe => ru }
def getSettings[T](paramObj: T)(implicit tag: TypeTag[T]) {
val m = ru.runtimeMirror(getClass.getClassLoader)
val classType = ru.typeOf[T].typeSymbol.asClass
val cm = m.reflectClass(classType)
val constructor = tag.tpe.declaration(ru.nme.CONSTRUCTOR).asMethod
val constructorMethod = cm.reflectConstructor(constructor)
val args = constructor.asMethod.paramss.head map { p => (p.name.decoded, p.typeSignature) }
println(args)
}
When Invoked like so:
scala> getSettings(MyClass)
List()
Have that output?? Is the constructor not 2 arguments??
I must be missing something really obvious here. The documentation doesn't cover scenarios quite like this.
http://docs.scala-lang.org/overviews/reflection/overview.html
getSettings(MyClass)
MyClass is the companion object of class MyClass. It has no constructor parameters.
You should rewrite your code like this:
def getSettings[T]()(implicit tag: TypeTag[T]) {
...
}
scala> getSettings[MyClass]
List((param1,String), (param2,String))

Macros: path dependent type inference confusion

I tried to simplify the creation of ASTs, but got a weird error message:
case class Box(i: Int)
object M {
import language.experimental.macros
import scala.reflect.makro.Context
case class meth(obj: String, method: String)(implicit val c: Context) {
import c.universe._
def apply(xs: Tree*) =
Apply(Select(Ident(obj), newTermName(method)), xs.toList)
}
def box(n: Int): Box = macro boxImpl
def boxImpl(c: Context)(n: c.Expr[Int]): c.Expr[Box] = {
import c.universe._
implicit val cc: c.type = c
n.tree match {
case arg # Literal(Constant(_)) =>
meth("Box", "apply").apply(arg)
}
}
}
Error:
<console>:26: error: type mismatch;
found : c.universe.Literal
required: _2.c.universe.Tree where val _2: M.meth
possible cause: missing arguments for method or constructor
meth("Box", "apply").apply(arg)
^
Is it possible to infer the correct types into class meth? Or is there a workaround for the problem?
EDIT: Based on #retronyms answer I got this to work:
object M {
import language.experimental.macros
import scala.reflect.makro.Context
def meth(implicit c: Context) = new Meth[c.type](c)
class Meth[C <: Context](val c: C) {
import c.universe._
def apply(obj: String, method: String, xs: Tree*) =
Apply(Select(Ident(obj), newTermName(method)), xs.toList)
}
def box(n: Int): Box = macro boxImpl
def boxImpl(c: Context)(n: c.Expr[Int]): c.Expr[Box] = {
import c.universe._
implicit val cc: c.type = c
n.tree match {
case arg # Literal(Constant(_)) =>
c.Expr(meth.apply("Box", "apply", arg))
}
}
}
Constructors are not currently allowed to have dependent method types (SI-5712). It's on the radar to be fixed, hopefully for 2.10.1 or 2.11.
In the meantime, you can follow the pattern I used in macrocosm to reuse code within macro implementations.