Here is a code snippet that tries to reproduce a problem I am facing while implementing an internal DSL:
object testObj {
implicit def foo1[T <% Function1[Int, Int]](fun: T): String = "foo1"
implicit def foo2[T <% Function2[Int, Int, Int]](fun: T): String = "foo2"
def test(arg: String): Unit = {}
test((x:Int) => 5) //Ambiguous implicit conversion error
test((x:Int, y:Int) => 5) //Ambiguous implicit conversion error
}
I am getting ambiguous implicit conversions errors at the shown locations:
<console>:21: error: type mismatch;
found : Int => Int
required: String
Note that implicit conversions are not applicable because they are ambiguous:
both method foo1 in object testObj of type [T](fun: T)(implicit evidence$1: T => (Int => Int))String
and method foo2 in object testObj of type [T](fun: T)(implicit evidence$2: T => ((Int, Int) => Int))String
are possible conversion functions from Int => Int to String
test((x:Int) => 5) //Ambiguous implicit conversion error
^
However commenting one of the implicits does not solve the problem. I am using view bounds since finally I want to chain the implicits. Note that the code snippet given above does not involve implicit chaining.
I was expecting that foo1 implicit conversion would be applicable for the first test application whereas foo2 implicit conversion would be applicable for the second test application.
I don't understand how both the implicits are applicable to both the testfunction applications. Why is this happening and how to make this work?
Edit:
If I don't use view bounds, it works fine as shown below. But I want to use view bounds since I want to chain the implicits the way it is explained in the post How can I chain implicits in Scala?.
implicit def foo1(fun: Function1[Int, Int]): String = "foo1"
implicit def foo2(fun: Function2[Int, Int, Int]): String = "foo2"
def test(arg: String): Unit = {}
test((x:Int) => 5) //No error
test((x:Int, y:Int) => 5) //No error
I'm afraid this won't work. View bounds are just not taken into account when resolving implicits and thus you can't chain implicits. That is be design, because such chaining could create some very unreadable code. The only option I see is to create a new implicit conversion for each possible chain of conversions.
Related
Given a made-up F type-class:
scala> trait F[A] {}
defined trait F
and this definition, which uses a context bound to require that the input A has a type-class instance of F:
scala> def f[A : F](x: A) = ???
f: [A](x: A)(implicit evidence$1: F[A])Nothing
I defined a Person and type-class instance:
scala> case class Person(name: String)
defined class Person
scala> implicit val person: F[Person] = new F[Person] {}
person: F[Person] = $anon$1#262b2c86
And the following compiles:
scala> f(Person("foo"))
scala.NotImplementedError: an implementation is missing
But, there's no String implementation, so it fails.
scala> f("foobar")
<console>:17: error: could not find implicit value for evidence parameter of type F[String]
f("foobar")
^
I then defined an F[String] using:
scala> implicit def fInstance(x: String) = new F[String] {}
fInstance: (x: String)F[String]
But, I can't run:
scala> f("foobar")
<console>:18: error: could not find implicit value for evidence parameter of type F[String]
f("foobar")
^
since I do not have an implicit F[String], but rather a String => F[String].
What's the proper way to use such an implicit def to meet the F[String] constraint, i.e. call the f function successfully with a type of String?
I got it to work via:
scala> implicit val x: F[String] = implicitly[String => F[String]].apply("foobar")
x: F[String] = $anon$1#7b7fdc8
scala> f("foobar")
scala.NotImplementedError: an implementation is missing
at scala.Predef$.$qmark$qmark$qmark(Predef.scala:230)
at .f(<console>:12)
... 33 elided
But I'm not sure if it's the right/clean way to do it.
You defined an implicit conversion. If you want to use a def to provide typeclass instances you just write the same as you'd write an implicit val but replace val with def.
implicit def fInstance = new F[String] {}
Normally you only use a def if you need type parameters, like here.
implicit def fInstance[A] = new F[List[A]] {}
Or
implicit def fInstance[A](implicit ev: F[A]) = new F[List[A]] {}
Your fInstance defines an implicit conversion, i.e. a way to turn a String into F[String]. For generating a typeclass instance, a method accepting implicit parameters can be used:
implicit def fInstance(implicit x: String) = new F[String] {}
it is typically used in FP libraries to derive one typeclass from another:
implicit def optionMonoid[A](implicit S: Semigroup[A]): Monoid[Option[A]] = ???
// or, which is the same
// implicit def optionMonoid[A: Semigroup]: Monoid[Option[A]] = ???
The idea is that F[String] can operate on any String in general, not being dependent on actual arguments provided into function. Of course, you can always provide instances explicitly:
f("foobar")(new F[String] { })
As a follow-up, the important part of typeclasses is that you can define them ad-hoc, i.e. not having access to definitions of F and String at all, and you are forced to scope implicits in Scala and import them, so it's totally ok.
Here is a simpler version of your definition (and you can remove implicit from fInstance):
implicit val singleFInstance: F[String] = fInstance("") // or fInstance("foobar"), etc.
Whether this is the right thing to do, very much depends on what F and f are supposed to mean.
But generally speaking: if F is really a type-class, fInstance(string) gives different results depending on the string (not just different instances, but different behavior), and f's signature is correct, then this is wrong and you should accept that calling f("foobar") isn't meaningful.
Given:
scala> trait Resource[A] { def f: String }
defined trait Resource
scala> case class Foo(x: String)
defined class Foo
And then an implicit:
scala> implicit def fooToResource(foo: Foo): Resource[Foo] =
new Resource[Foo] { def f = foo.x }
The following works:
scala> implicitly[Resource[Foo]](Foo("foo")).f
res2: String = foo
I defined a function:
scala> def f[A](x: A)(implicit ev: Resource[A]): String = ev.f
f: [A](x: A)(implicit ev: Resource[A])String
However, the following code fails to compile:
scala> f(Foo("foo"))
<console>:17: error: could not find implicit value for parameter ev: Resource[Foo]
f(Foo("foo"))
Secondly, then I tried:
scala> f2(Foo("bippy"))
<console>:17: error: could not find implicit value for parameter ev: Resource[Foo]
f2(Foo("bippy"))
^
Lastly, I attempted:
scala> def g(foo: Foo)(implicit ev: Resource[Foo]): String = ev.f
g: (foo: Foo)(implicit ev: Resource[Foo])String
scala> g(Foo("5"))
<console>:17: error: could not find implicit value for parameter ev: Resource[Foo]
g(Foo("5"))
^
However, it failed too. How can I fix f?
Ok with Peter Neyens' answer, this is not a typeclass, this is an implicit conversion, which you should avoid - there should have been some warning, asking that you import scala.language.implicitConversions.
As a complement, here is why the first implicitly works:
Implicitly is just:
def implicitly[T](implicit ev: T): T = e
When you write implicitly[T] without supplying a parameter, it will look for an implicit of type T in scope and return it. However, you call implicitly with a parameter (I believe there is no legitimate reason to do that, ever), so it would just return your parameter, Foo("foo"), an instance of Foo. Except that you explicitly stated that T should be Resource[Foo]. If you had written a type ascription, such as (Foo("foo"): Resource[Foo]), it would have worked the same way. implicitly is not relevant here.
The point is that Foo("foo") is not of the expected type Resource[Foo], but just a Foo. The compiler would reject that, except that at this point, the implicit conversion you defined above kicks in, and your Foo instance is transformed into a Resource[Foo]. Then, you can call f.
Next, you call your f(Foo("foo")). There is an implicit parameter, however this time, you don't supply it. So the compiler looks for one (while it did no such thing the first time), and as there is no such instance, fails.
The implicit def fooToResource is not a type class instance, but does return one if you supply a Foo, that's the reason the following line works :
implicitly[Resource[Foo]](Foo("foo")).f
A solution would be to change the Resource.f function to take a parameter of type A :
trait Resource[A] {
def f(a: A): String
}
You then could define a Resource type class instance for Foo as follows:
case class Foo(x: String)
implicit val fooResource = new Resource[Foo] {
def f(foo: Foo) = foo.x
}
We can rewrite f to use the changed Resource :
def f[A](a: A)(implicit resA: Resource[A]): String = resA.f(a)
Which does what (I think) you need :
f(Foo("hello world")) // String = hello world
i'm trying to understand the behavior of the compiler in this situation
object ImplicitTest extends App {
def foo[T](implicit x: (String => T)): T = ???
implicit val bar = (x: String) => x.toInt
foo
}
the code above does not compile and gives the following error:
ambiguous implicit values: both method $conforms in object Predef of
type [A]⇒ <:<[A,A] and value bar in object ImplicitTest of type ⇒ String ⇒
Int match expected type String ⇒ T
as the error says my implicit value is conflicting with another implicit defined in Predef... based on this it seems there is no way to declare an implicit parameter to a function converting a value from a known type to an unknown (generic) type.
Is this due to some technical limitation on the compiler or is just the way it is supposed to work, and i'm violating some constraints i'm not aware of?
You're not providing a type parameter to foo when you call it (and there is no other way to infer it, for the following reason), so the compiler is having trouble finding the right one, and the right implicit.
You have the implicit bar: String => Int in scope, but you also have implicits in Predef that create instances of =:= and <:< which both extend A => B, and create implicit String => As. The compiler is looking for some implicit function String => T for foo, but it's not sure which one, and you have multiple in scope. bar will not take precedence because you haven't specified the specific String => T it's looking for.
This will work:
def foo[T](implicit x: (String => T)): T = ???
implicit val bar = (x: String) => x.toInt
foo[Int]
I have the following (simplified) code:
case class Value[T](value: T)
trait Absable[In,Out] {
def absoluteValue(in: In): Out
}
implicit class AbsValue[In, Out](in: Value[In]) {
def abs()(implicit ev: Absable[In, Out]): Value[Out] = Value(ev.absoluteValue(in.value))
}
implicit def AbsNumeric[A : Numeric] = new Absable[A, A] {
def absoluteValue(in: A) = implicitly[Numeric[A]].abs(in)
}
Now I want to use the abs function on a Value:
scala> Value(-3).abs()
res3: Value[Int] = Value(3)
scala> Value(-3).abs
<console>:14: error: could not find implicit value for parameter ev: Absable[Int,Nothing]
Value(-3).abs
^
I added an empty argument list in front of the implicit arguments to give callers more flexibility, but now when I omit the empty list at the call site the compiler can't find the implicit... So now instead of more flexibility callers get confusing compile errors.
I don't understand how leaving off the argument list can affect the type inference or implicit resolution.
I am using scala 2.11.6
Is there something I've got wrong with the following fragment:-
object Imp {
implicit def string2Int(s: String): Int = s.toInt
def f(i: Int) = i
def main(args: Array[String]) {
val n: Int = f("666")
}
}
I get the following from the 2.8 compiler:-
Information:Compilation completed with 1 error and 0 warnings
Information:1 error
Information:0 warnings
...\scala-2.8-tests\src\Imp.scala
Error:Error:line (4)error: type mismatch;
found : String
required: ?{val toInt: ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method string2Int in object Imp of type (s: String)Int
and method augmentString in object Predef of type (x:String)scala.collection.immutable.StringOps
are possible conversion functions from String to ?{val toInt: ?}
implicit def string2Int(s: String): Int = s.toInt
What is happening is that Java does not define a toInt method on String. In Scala, what defines that method is the class StringOps (Scala 2.8) or RichString (Scala 2.7).
On the other hand, there is a method toInt available on Int as well (through another implicit, perhaps?), so the compiler doesn't know if it is to convert the string to StringOps, through the defined implicit, or to Int, through your own implicit.
To solve it, call the implicit explicitly.
object Imp {
implicit def string2Int(s: String): Int = augmentString(s).toInt
def f(i: Int) = i
def main(args: Array[String]) {
val n: Int = f("666")
}
}
There is already an implicit conversion in scope, from scala.Predef. You don't need to declare your own implicit conversion to add a toInt method to a String. You have 3 options (I'd go for the last one!):
Change your method name to something like asInt
Unimport the conversion in Predef
Don't bother defining your own and use instead the toInt that comes bundled with the scala library
Note that scala will only make use of an in-scope implicit conversion if it is unique.
I think I have a workaround.
If I create a RichString from the String argument, the implicit conversion occurs from RichString to Int using the implicit method I provide (this works for 2.7.x and 2.8). If I remove my implicit I get a type error.
object Imp {
implicit def string2Int(rs: RichString): Int = rs.toInt
def f(i: Int) = i
def main(args: Array[String]) {
val n: Int = f(new RichString("666"))
println(n)
}
}
I'm still confused as to why both implicits came into scope and clashed when I provided an implicit and as to why the Predef one didn't come into scope when I didn't provide one for String to Int. I suppose the question about an implicit conversion from String to Int remains open.