I have posted this question in scala-user forum,
https://groups.google.com/forum/#!topic/scala-user/xlr7KmlWdWI
and I received an answer which I am happy with. However, at the same time I want to make sure if that is the only conclusion. Thanks
My question is, say, I have,
trait Combinable[A] {
def join[B](l: List[A]): B
}
When I implement this trait with A as String and B as Int, for example,
class CombineString extends Combinable[String] {
override def join[Int](strings: List[String]) = string.size
}
Obviously, Int, next to join method, is not the Scala integer class and
compiling this code will fail. Alternatively, I could rewrite my trait as
trait Combinable[A, B] {
def join(l: List[A]): B
}
or
trait Combinable[A] {
def join[B](l: List[A])(f: List[A] => B): B
}
My question is, how can I implement the trait as defined in the first example as it is? If the first example has no practical use because of the way it is defined, why does the compiler not complaints? Thanks again.
You can not expect for compiler to understand what type combinations make sense for you, but you can specify this sense as relation between types in term of multiparameter implicits.
Result is basically combination of two of your rejected approaches, but with desired syntax.
First of two rejected forms became implicit type:
trait Combine[A, B] {
def apply(l: List[A]): B
}
Next you can define appropriate type combinations and their meaning
implicit object CombineStrings extends Combine[String, String] {
def apply(l: List[String]) = l.mkString
}
implicit object CombineInts extends Combine[Int, Int] {
def apply(l: List[Int]) = l.sum
}
implicit object CombinableIntAsString extends Combine[Int, String] {
def apply(l: List[Int]) = l.mkString(",")
}
Finally we modify second rejected form that hides f argument for implicit resulution:
trait Combinable[A] {
def join[B](l: List[A])(implicit combine: Combine[A, B]): B = combine(l)
}
Now you can define
val a = new Combinable[String] {}
val b = new Combinable[Int] {}
And check that
a.join[String](List("a", "b", "c"))
b.join[Int](List(1, 2, 3))
b.join[String](List(1, 2, 3))
runs nice while
a.join[Int](List("a", "b", "c"))
makes compiler cry until you could provide evidence of practical use of relation between String and Int in form of implicit value
My question is, how can I implement the trait as defined in the first example as it is?
class CombineString extends Combinable[String] {
override def join[B](strings: List[String]) = null.asInstanceOf[B]
// or, for that matter, anything and then .asInstanceOf[B]
}
How could the compiler know that's not what you want?
Related
I want to make a simple Scala.math.Ordering wrapper instance for java.lang.Comparable. I would think this is standard, but I don't see anything similar in JavaConversions.
Can someone get something like this to work:
object ComparableOrdering[A <: Comparable[A]] extends Ordering[A] {
def compare(a: A, b: A): Int = a.compareTo(b)
}
Actually to handle classes like
interface A {}
class B implements A, Comparable<A> {}
it should be more like:
object ComparableOrdering[A <: Comparable[B] with B] extends Ordering[A] {
def compare(a: A, b: A): Int = a.compareTo(b)
}
Can anyone get this working?
The standard library already provides these instances via Ordering.ordered. For example, if you have a class like this:
class Foo(val i: Int) extends Comparable[Foo] {
def compareTo(that: Foo): Int = this.i - that.i
}
You'll automatically have an instance available:
scala> Ordering[Foo].lt(new Foo(0), new Foo(1))
res0: Boolean = true
The signature of Ordering.ordered isn't quite the same as yours:
implicit def ordered[A](implicit arg0: (A) => Comparable[A]): Ordering[A]
This works because the standard library provides implicit "conversion" functions that will up-cast any type to any of its supertypes.
If for some reason you wanted to define your own instances, you could do something like this:
implicit def comparableOrdering[A <: Comparable[A]]: Ordering[A] =
new Ordering[A] {
def compare(a: A, b: A): Int = {
println("Using custom instance for Comparable things")
a.compareTo(b)
}
}
And then:
scala> Ordering[Foo].lt(new Foo(0), new Foo(1))
Using custom instance for Comparable things
res0: Boolean = true
I'd guess that the standard library doesn't define these instances this way for reasons related to implicit prioritization, but the instances for Ordering are a mess and the question of why they use the A => Comparable[A] approach probably isn't worth thinking too hard about.
I've been experimenting with implicit conversions, and I have a decent understanding of the 'enrich-my-libray' pattern that uses these. I tried to combine my understanding of basic implicits with the use of implicit evidence... But I'm misunderstanding something crucial, as shown by the method below:
import scala.language.implicitConversions
object Moo extends App {
case class FooInt(i: Int)
implicit def cvtInt(i: Int) : FooInt = FooInt(i)
implicit def cvtFoo(f: FooInt) : Int = f.i
class Pair[T, S](var first: T, var second: S) {
def swap(implicit ev: T =:= S, ev2: S =:= T) {
val temp = first
first = second
second = temp
}
def dump() = {
println("first is " + first)
println("second is " + second)
}
}
val x = new Pair(FooInt(200), 100)
x.dump
x.swap
x.dump
}
When I run the above method I get this error:
Error:(31, 5) Cannot prove that nodescala.Moo.FooInt =:= Int.
x.swap
^
I am puzzled because I would have thought that my in-scope implict conversion would be sufficient 'evidence' that Int's can be converted to FooInt's and vice versa. Thanks in advance for setting me straight on this !
UPDATE:
After being unconfused by Peter's excellent answer, below, the light bulb went on for me one good reason you would want to use implicit evidence in your API. I detail that in my own answer to this question (also below).
=:= checks if the two types are equal and FooInt and Int are definitely not equal, although there exist implicit conversion for values of these two types.
I would create a CanConvert type class which can convert an A into a B :
trait CanConvert[A, B] {
def convert(a: A): B
}
We can create type class instances to transform Int into FooInt and vise versa :
implicit val Int2FooInt = new CanConvert[Int, FooInt] {
def convert(i: Int) = FooInt(i)
}
implicit val FooInt2Int = new CanConvert[FooInt, Int] {
def convert(f: FooInt) = f.i
}
Now we can use CanConvert in our Pair.swap function :
class Pair[A, B](var a: A, var b: B) {
def swap(implicit a2b: CanConvert[A, B], b2a: CanConvert[B, A]) {
val temp = a
a = b2a.convert(b)
b = a2b.convert(temp)
}
override def toString = s"($a, $b)"
def dump(): Unit = println(this)
}
Which we can use as :
scala> val x = new Pair(FooInt(200), 100)
x: Pair[FooInt,Int] = (FooInt(200), 100)
scala> x.swap
scala> x.dump
(FooInt(100), 200)
A =:= B is not evidence that A can be converted to B. It is evidence that A can be cast to B. And you have no implicit evidence anywhere that Int can be cast to FooInt vice versa (for good reason ;).
What you are looking for is:
def swap(implicit ev: T => S, ev2: S => T) {
After working through this excercise I think I have a better understanding of WHY you'd want to use implicit evidence serves in your API.
Implicit evidence can be very useful when:
you have a type parameterized class that provides various methods
that act on the types given by the parameters, and
when one or more of those methods only make sense when additional
constraints are placed on parameterized types.
So, in the case of the simple API given in my original question:
class Pair[T, S](var first: T, var second: S) {
def swap(implicit ev: T =:= S, ev2: S =:= T) = ???
def dump() = ???
}
We have a type Pair, which keeps two things together, and we can always call dump() to examine the two things. We can also, under certain conditions, swap the positions of the first and second items in the pair. And those conditions are given by the implicit evidence constraints.
The Programming in Scala book gives a nice example of how this technique
is used in Scala collections, specifically on the toMap method of Traversables.
The book points out that Map's constructor
wants key-value pairs, i.e., two-tuples, as arguments. If we have a
sequence [Traversable] of pairs, wouldn’t it be nice to create a Map
out of them in one step? That’s what toMap does, but we have a
dilemma. We can’t allow the user to call toMap if the sequence is not
a sequence of pairs.
So there's an example of a type [Traversable] that has a method [toMap] that can't be used in all situations... It can only be used when the compiler can 'prove' (via implicit evidence) that the items in the Traversable are pairs.
There is a type that can be parametrized by a certain restricted set of types:
trait Base[T] { def f(t: T): List[T] }
implicit object StringBase extends Base[String] {
override def f(t: String) = t.toList.map(c => String.valueOf(c))
}
implicit object IntBase extends Base[Int] {
override def f(t: Int) = List(t,t,t)
}
Now, I can define a function that takes a collection of a specific type and processes it:
def consume[T : Base](xs: Seq[T]) =
xs.map(x => implicitly[Base[T]].f(x).mkString("-"))
How do I define a function that takes a sequence of objects for types of which there exists an implicit conversion to Base and do the same? In a type-safe way, of course.
If I was not entirely clear, here's what I'd like to have:
consume(Seq(1,"asd", 3)) // => Seq("1-1-1", "a-s-d", "3-3-3")
I'm sure I can achieve it with shapeless' HList, but what about core Scala? Anyway, putting shapeless tag in case functionally inclined guys are willing to help.
import shapeless._
import ops.hlist.Mapper
import ops.hlist.ToList
trait Base[T] { def f(t: T): List[T] }
implicit object StringBase extends Base[String] {
override def f(t: String) = t.toList.map(c => String.valueOf(c))
}
implicit object IntBase extends Base[Int] {
override def f(t: Int) = List(t,t,t)
}
object base extends Poly1 {
implicit def forBase[A : Base] = at[A](x => implicitly[Base[A]].f(x))
}
def consume[T <: HList, Inter <: HList](xs: T)
(implicit
mapBase: Mapper.Aux[base.type, T, Inter],
interToList: ToList[Inter, List[Any]]): Seq[String] = {
xs.map(base).toList.map(_.mkString("-"))
}
Two key parts:
object base extends Poly1 : This is a polymorphic function only defined on types with a Base typeclass instance. It calls Base.f on its arg.
The implicits and type params in consume :
T is our input HList type. Inter is an intermediate type variable that is the output type of the result of mapping base over T.
mapBase: Mapper.Aux[base.type, T, Inter] : This is evidence that if we map base over T we get Inter. We need this to call .map on the incoming hlist. By putting it in our implicits list, we just require that it exists when the function is called. Shapeless will generate this for us if it can. If it can't, it most likely means that you forgot to define a Base instance for a type in T
interToList: ToList[Inter, List[Any]] : This is evidence that you can convert the HList Inter to a List[List[Any]]. So List[Any] must be the least-upperbound type of all the types in Inter. Once again, by putting it in the input implicits, we just require that shapeless can generate this for us. This is just boilerplate to prove to the compiler that we can call toList and get a List[List[Any]]. I haven't found a way to avoid this and the Inter variable in my experiences sadly.
Now thanks to all those implicits, we just call xs.map(base) to get an HList out with the appropriate Base.f applied. Then we call .toList to get a List[List[Any]]. Then we map over those List[Any]s and mkString with dashes as you wanted. And out comes our Seq[String]!
Here is it working in the REPL:
scala> consume(1 :: "asd" :: 3 :: HNil)
res0: Seq[String] = List(1-1-1, a-s-d, 3-3-3)
Here is dirty hack for consume method. Not super type safe and nice but may be fine as a workaround.
trait Base[T] { def f(t: T): List[T] }
implicit object StringBase extends Base[String] {
override def f(t: String) = t.toList.map(c => String.valueOf(c))
}
implicit object IntBase extends Base[Int] {
override def f(t: Int) = List(t,t,t)
}
case class Consumable[T](v: T, base: Base[T])
implicit def toConsumable[T](v: T)(implicit base: Base[T], ev: ClassTag[T]) =
Consumable(v, base)
def consume(xs: Consumable[_]*) =
xs.map(x => x.base.asInstanceOf[Base[Any]].f(x.v).mkString("-"))
println(consume(1, 2, 3))
println(consume("a", "b", "c"))
println(consume(1, 2, "a", "b", "c"))
I have the following use case which occurs often in my code:
A Collection[A]
An implicit conversion A to B
and I want to obtain a collection of B. I can use implicitly like the following:
case class Items(underlying:List[B])
import B._
def apply(a:List[A]):Items = {
val listOfB= a.map {implicitly[A=>B]}
Items(listOfB)
}
What is the most elegant way to do that in Scala, maybe with the help of Scalaz of doing the same?
Edit: the goal of my question is to find an idiomatic way, a common approach among libraries/developers. In such a sense developing my own pimp-my-library solution is something I dislike, because other people writing my code would not know the existence of this conversion and would not use it, and they will rewrite their own. I favour using a library approach for this common functions and that's why I am wondering whether in Scalaz it exists such a feature.
It's pretty straightforward if you know the types. First implicit conversion from A to B:
implicit def conversion(a: A): B = //...
then you need implicit conversion from List[S] to List[T] where S and T are arbitrary types for which implicit conversion from S to T exists:
implicit def convList[S, T](input: List[S])(implicit c: S => T): List[T] =
input map c
This should then work:
val listOfA: List[A] = //...
val listOfB: List[B] = listOfA
which is resolved by the compiler to:
val listOfB: List[B] = convList(listOfA)(conversion)
where S is A and T is B.
I wouldn't use an implicit conversion here, but a view bound in the class:
case class Foo(x: Int)
case class Bar(y: Int)
implicit def foo2Bar(foo: Foo) = Bar(foo.x)
case class Items[A <% Bar](xs: List[A]) {
def apply(x: Int): Bar = xs(x)
}
You can now create an instance of Items with a list of Foo and internally use them, as if they were Bars.
scala> Items(List(Foo(1)))
res8: Items[Foo] = Items(List(Foo(1)))
scala> res8(0)
res9: Bar = Bar(1)
edit:
Some clarification, on why I would not use an implicit conversion:
Implicit conversions can be dangerous, when they are in scope and accidentally convert things, that they shouldn't convert. I would always convert stuff explicitly or via view bounds, because then I can control it, also implicit conversion may shrink the size of your code, but also makes it harder to understand for others. I would only use implicit conversion for the 'extend my library' pattern.
edit2:
You could however add a method to the collection types, that does this conversion, if such a method is in scope:
trait Convertable[M[A], A] {
def convertTo[B](implicit f: A => B): M[B]
}
implicit def list2Convertable[A](xs: List[A]) = new Convertable[List, A] {
def convertTo[B](implicit f: A => B) = xs.map(f)
}
scala> implicit def int2String(x: Int) = x.toString
int2String: (x: Int)String
scala> List(1,2,3).convertTo[String]
res0: List[String] = List(1, 2, 3)
Instead of using another implicit conversion here, I would probably use a typeclass instead, but I think you get the basic idea.
Works starting with Scala 2.10:
implicit class ListOf[A](val list: List[A]) {
def of[B](implicit f: A => B): List[B] = list map f
}
implicit def int2String(i: Int) = i.toString
// Usage
List(1,2,3).of[String]
In my code, I'm using a more general version adapted from Tomasz' solution above which handles all Traversable instances
/** Implicit conversion for Traversable instances where the elements are convertable */
implicit def convTrav[S, T, I[S] <: Traversable[S]](input: I[S])(implicit c: S => T): I[T] =
(input map c).asInstanceOf[I[T]]
(This is working for me, although I'm keen to know if any more experienced Scala programmers think this is a bad idea for any reason, apart from the usual caveats about implicit conversions)
Hi I read the interesting post from Debasish about the implicitly function. I have wrote this code:
def find[C <: Business](id: String) = {
collection.findOneByID(id).map(x=> implicitly[DBObject => C].apply(x))
}
but it fails to compile with this compiler message:
could not find implicit value for parameter e: (com.mongodb.casbah.commons.Imports.DBObject) => C
what is my fault? anyone can help me?
UPDATE
My idea was this:
find is declared in a trait don't know nothing about DBObject, I don't want to put this dependency.
trait BusinessRepository {
def find[C <: Business](id: String): Option[C]
}
class MongoBusinessRepository {
val collection = ..
def find[C <: Business](id: String): Option[C] = {
collection.findOneByID(id).map(x=> implicitly[DBObject => C].apply(x))
}
implicit def DBObject2Hotel(x: DBObject): Hotel = {
// ...
// returning Hotel
}
}
case class Hotel(...) extends Business(...)
implicitly is just a convenience method to look up an implicit value that you know already exists. So it fails to compile when there is no such implicit value in scope.
A possible use case is when you use shortcut syntax for context bounds:
def find[C: Numeric](a: C, b: C): C = implicitly[Numeric[C]].plus(a, b)
Of course, in this example, the explicit form is less verbose
def find[C](a: C, b: C)(implicit n: Numeric[C]): C = n.plus(a, b)
You will find more thorough explanations in this Stackoverflow thread.
What I imagine you had in mind with your method is rather
def find[C <: Business](id: String)(implicit fun: DBObject => C) =
collection.findOneByID(id).map(fun)
I think that the problem comes from the fact that Scala compiler try to find an implicit definition of a function DBObject => C and that the only implicit definition that he can find is DBObject => Hotel that could be a solution but it's not strict. With your solution, the compiler is not able to know what should be C.
Maybe you should consider defining a DBObject2Business and so implicitly define a DBObject => Business function, or change your design to define C in a concrete class.