I have a have an implicit class like this
private[this] implicit class OptionListUtil[A, B <: List[A]](option: Option[B]) {
def defaultMap[C](f: A => C): Seq[C] = option.getOrElse(Seq.empty[A]).map(f)
But when I go ahead and call it on a Option[List[A]], I get the value defaultMap is not a member of Option[List[A]]
Intellij is not giving any hints so I'm pretty lost
Generally, if a type parameter only appears once it's suspicious. In this case B is actually useless and you can simplify OptionListUtil to
private[this] implicit class OptionListUtil[A](option: Option[List[A]]) {
def defaultMap[C](f: A => C): Seq[C] = option.getOrElse(Seq.empty[A]).map(f)
}
because Option is covariant. This is much simpler for type inference to handle.
Go with this instead:
implicit class OptionListUtil[A,B](option: Option[B])(implicit ev: B <:< List[A]) {
def defaultMap[C](f: A => C): Seq[C] = option.toSeq.flatMap(_.map(f))
}
The current scala compiler can't infer the type A in your B <: List[A] quite right yet. Asking for the implicit evidence of <:< in these cases helps the compiler with type inference.I read somewher that the new dotty compiler apparently doesn't have this issue.
Looks like another way to address this is with higher kinded generics with the class signature like:
private[this] implicit class OptionListUtil[A, B[A] <: List[A]](option: Option[B[A]])
Related
I am dipping my toes in higher kinded types, exploring a very basic Scala example:
trait Mappable[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
object Mappable {
implicit object MappableOption extends Mappable[Option] {
def map[A, B](fa: Option[A])(f: A => B): Option[B] = fa.map(f)
}
implicit object MappableSeq extends Mappable[Seq] {
def map[A, B](fa: Seq[A])(f: A => B): Seq[B] = fa.map(f)
}
}
def bananaTuple[F[_], T](f: F[T])(implicit F: Mappable[F]): F[(String, T)] =
F.map(f)(("banana", _))
This works:
bananaTuple(Option(42)) // Some((banana,42))
bananaTuple(Seq(42)) // List((banana,42))
But this does not compile:
bananaTuple(Some(42))
bananaTuple(List(42))
The compile errors I get:
could not find implicit value for parameter F: ch.netzwerg.hkt.HigherKindedTypes.Mappable[Some] bananaTuple(Some(42))
not enough arguments for method bananaTuple: (implicit F: ch.netzwerg.hkt.HigherKindedTypes.Mappable[Some])Some[(String, Int)]. Unspecified value parameter F. bananaTuple(Some(42))
How can I bring variance into the game?
We can make this work with a little more parameteric polymorphism:
object MappableExample {
trait Mappable[F[_]] {
type Res[_]
def map[A, B](f: A => B)(c: F[A]): Res[B]
}
implicit def seqMappable[C[X] <: Seq[X]] = new Mappable[C] {
type Res[X] = Seq[X]
override def map[A, B](f:A => B)(c: C[A]): Seq[B] = c.map(f)
}
implicit def optionMappable[C[X] <: Option[X]]: Mappable[C] = new Mappable[C] {
type Res[X] = Option[X]
override def map[A, B](f: A => B)(c: C[A]): Option[B] = c.map(f)
}
def map[A, B, C[_]](xs: C[A])(f: A => B)(implicit mappable: Mappable[C]): mappable.Res[B] = {
mappable.map(f)(xs)
}
def main(args: Array[String]): Unit = {
println(map(List(1,2,3))(("banana", _)))
println(map(Some(1))(("banana", _)))
}
}
Yields:
List((banana,1), (banana,2), (banana,3))
Some((banana,1))
The compiler now infers Some as Mappable[Some]#Res[Int] and Mappable[List]#Res[Int] which is quite ugly. One would expect the compiler to actually be able to infer the right type without needing for any co/contravariance on the Mappable trait, which we can't do since we're using it in an invariant position.
Subtype polymorphism allows us to pass values of a certain type or any of its subtypes to a method. If a method takes a value of type Fruit, we can also pass an Apple inside (an apple is a fruit after all). So if you want to be able to pass a Mappable.MappableOption to your bananaTuple method, you have to make that MappableOption a subtype of MappableSome (since the type of your first parameter of bananaTuple dictates the implicit one). This means that you want your Mappable contravariant (if Some <: Option, then Mappable[Some] >: Mappable[Option]).
But you cannot have Mappable[F[_]] contravariant in F because F appears in covariant position of map (as a function parameter). Note that F also appears in contravariant position of map (as a return value).
If you manage to make Mappable[F[_]] contravariant in F, it should work, but I'm not sure if making it contravariant makes sense. That is, if you want a subtype relationship such as e.g. Apple <: Fruit to result in Mappable[Apple] >: Mappable[Fruit] (this would not compile since Apple and Fruit are not type constructors, but I'm just using simple types to make a point here).
Making a type contravariant in its type and solving the problem of contravariant type appearing in covariant position is a common problem and perhaps it's better if you search for it elsewhere (here is one example). I still think that it's better to provide an implicit object for every type you want to use, that is, to provide separate implicit objects for e.g. Seq and List.
In Scala there's a class <:< that witnesses a type constraint. From Predef.scala:
sealed abstract class <:<[-From, +To] extends (From => To) with Serializable
private[this] final val singleton_<:< = new <:<[Any,Any] { def apply(x: Any): Any = x }
implicit def $conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A]
An example of how it's used is in the toMap method of TraversableOnce:
def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U] =
What I don't understand is how this works. I understand that A <:< B is syntactically equivalent to the type <:<[A, B]. But I don't get how the compiler can find an implicit of that type if and only if A <: B. I assume that the asInstanceOf call in the definition of $conforms is making this possible somehow, but how? Also, is it significant that a singleton instance of an abstract class is used, instead of just using an object?
Suppose we've got the following simple type hierarchy:
trait Foo
trait Bar extends Foo
We can ask for proof that Bar extends Foo:
val ev = implicitly[Bar <:< Foo]
If we run this in a console with -Xprint:typer, we'll see the following:
private[this] val ev: <:<[Bar,Foo] =
scala.this.Predef.implicitly[<:<[Bar,Foo]](scala.this.Predef.$conforms[Bar]);
So the compiler has picked $conforms[Bar] as the implicit value we've asked for. Of course this value has type Bar <:< Bar, but because <:< is covariant in its second type parameter, this is a subtype of Bar <:< Foo, so it fits the bill.
(There's some magic involved here in the fact that the Scala compiler knows how to find subtypes of the type it's looking for, but it's a fairly generic mechanism and isn't too surprising in its behavior.)
Now suppose we ask for proof that Bar extends String:
val ev = implicitly[Bar <:< String]
If you turn on -Xlog-implicits, you'll see this:
<console>:9: $conforms is not a valid implicit value for <:<[Bar,String] because:
hasMatchingSymbol reported error: type mismatch;
found : <:<[Bar,Bar]
required: <:<[Bar,String]
val ev = implicitly[Bar <:< String]
^
<console>:9: error: Cannot prove that Bar <:< String.
val ev = implicitly[Bar <:< String]
^
The compiler tries the Bar <:< Bar again, but since Bar isn't a String, this isn't a subtype of Bar <:< String, so it's not what we need. But $conforms is the only place the compiler can get <:< instances (unless we've defined our own, which would be dangerous), so it quite properly refuses to compile this nonsense.
To address your second question: the <:<[-From, +To] class is necessary because we need the type parameters for this type class to be useful. The singleton Any <:< Any value could just as well be defined as an object—the decision to use a val and an anonymous class is arguably a little simpler, but it's an implementation detail that you shouldn't ever need to worry about.
I believe that a generic class may make one of its methods available only assuming that its type parameters conform to some additional restrictions, something like (syntax improvised on the spot):
trait Col[T] extends Traversable[T] {
def sum[T<:Int] :T = (0/:this)(_+_)
}
I guess I could use implicit parameters as evidence... Is there a language feature for this?
You can also use a type bound on the type parameter, which is enforced by an implicit argument:
trait Col[T] extends Traversable[T] {
def sum(implicit ev: T <:< Int) :T = (0/:this)(_+_)
}
<:< is actually a class, expressed in infix notation, defined in Predef.scala and explained in many places, including here
<:< means 'must be a subtype of'
You can also use =:= 'must be equal to' and X <%< Y 'must be viewable as' (ie. there is an implicit conversion to X from Y)
For a more detailed explanation of type constraints, see this SO question.
In this case you can only use an implicit parameter, as the type gets determined before the method call.
trait Col[T] extends Traversable[T] {
def sum(implicit num: Numeric[T]) :T = ???
}
If the method you are calling would be parameterized, you could use context bounds, which are just syntactic sugar for the implicit parameter bound to the type parameter:
def foo[A](implicit ev: Something[A]) = ???
is equivalent to
def foo[A : Something] = ???
there is another option involving implicit classes conversions
trait Col[T] extends Traversable[T]
implicit class ColInt[T <: Int](val v : Col[T]) extends AnyVal {
def sum : T = (0 /: v)(_ + _)
}
in this context you don't need the empty trait Col anymore, so you could further comprimize it to this:
implicit class ColInt[T <: Int](val v : Traversable[T]) extends AnyVal {
def sum : T = (0 /: v)(_ + _)
}
The advantage of this method is, that it tells the compiler, that type T is really a subtype of Int, so List[T] <: List[Int] is still valid in this context, and no explicit conversion needs to be added. The implicit parameter adds implicit conversions that wouldn't work on List[T], because it only introduces an implicit conversion from T to Int, not from List[T] to List[Int]
Suppose I have an abstract class Bar that takes a type parameter:
abstract class Bar[A] { def get: A }
and I have a function that wants to instantiate some Bar objects, call their get methods and return the results:
def foo[A, B <: Bar[A]]: Seq[A]
It seems a little verbose to have to provide A as a separate type parameter, since it's implicit in B. What I would really like is to say
def foo[B <: Bar[A]]: Seq[A]
but that doesn't compile. Is there a way to make foo more compact?
What Daniel said in the comment.
Perhaps using an abstract type member will help reduce the verbosity.
abstract class Bar {
type A
def get: A
}
def foo[B <: Bar]: Seq[B#A]
def baz[B <: Bar](b: B): Seq[B#A]
def taz[B <: Bar](b: B): Seq[b.A]
Scala 2.8.1
Take the following class hierarchy
abstract class A
class B extends A
class C extends A
Why is the scala compiler unable to find the implicit parameter for send when sending an instance of B below
implicit def routingKeyFor[T <: A](value: T) =
value.getClass.getSimpleName
implicit def routingKeyFor(value: C) = "custom C"
def send[T <: A](value: T)(implicit createRoutingKey: T => String):
Validation[Throwable, String] = Success(createRoutingKey(value))
val resultOfSendingB = send(new B)
val resultOfSendingC = send(new C)
Why is the compiler able to locate the value for the implicit parameter when the generic version of routingKeyFor is renamed?
implicit def someOtherName[T <: A](value: T) =
value.getClass.getSimpleName
The second implicit is shadowing the first one. Why is anyone's guess, and you might open an issue for it (after verifying that this wasn't reported before), but it might just be one of those things that throw a spanner into the works of type inference.