unwanted implicit argument resolution in higher order function map - scala

I'm having issues trying to map some methods defined with implicit arguments over an Option type.
Let's say I define a custom class and a trait with the aforementioned methods operating on said class
class MyClass
trait Processor {
def stringy(implicit arg: MyClass) = arg.toString
def lengthy(implicit arg: MyClass) = arg.toString.length
def inty(implicit arg: MyClass) = arg.toString.map(_.toInt).sum
}
Then I create an implementation with some tests
object TestProcessing extends Processor {
//Here everything works fine, the argument is passed explicitly
def test() {
val my = new MyClass
val res = List(stringy(my), lengthy(my), inty(my))
println(res.mkString("\n"))
}
//Still everything ok, the argument is passed implicitly
def testImplicit() {
implicit val my = new MyClass
val res = List(stringy, lengthy, inty)
println(res.mkString("\n"))
}
object Mapper {
//class wrapped in an Option
val optional = Some(new MyClass)
//trying to factor out common code
def optionally[T](processFunction: MyClass => T): Option[T] = optional map processFunction
//now the specific processing methods that should work on the optional value
def s: Option[String] = optionally(stringy)
def l: Option[Int] = optionally(lengthy)
def i: Option[Int] = optionally(inty)
/*
* Here the compiler complains that
*
*<console>:40: error: could not find implicit value for parameter arg: MyClass
* def s: Option[String] = optionally(stringy)
* ^
*<console>:41: error: could not find implicit value for parameter arg: MyClass
* def l: Option[Int] = optionally(lengthy)
* ^
*<console>:42: error: could not find implicit value for parameter arg: MyClass
* def i: Option[Int] = optionally(inty)
* ^
*/
}
}
While optionally is conceived to explicitly pass the optional value explicitly to its argument function, the compiler demands an implicit definition when I use it on the actual functions.
I have two possible solutions, neither of which is satisfactiory:
passing an implicit argument to optionally as in
optionally(implicit my => stringy)
avoid defining the argument to the specific functions as implicit, as in
def stringy(arg: MyClass)
Each solution defies the goal of achieving both readability and usability.
Is there a third way to go?

If I understand correctly, the problem is that the compiler doesn't seem recognize that you want to partially apply / lift the method to a function here (instead it "thinks" you want to leave out the implicit parameter), so doing that explicitly seems to work:
def s: Option[String] = optionally(stringy(_))
def l: Option[Int] = optionally(lengthy(_))
def i: Option[Int] = optionally(inty(_))

Related

Behaviour of context bounds and implicit parameter lists with regards to path dependent types

I always thought that context bounds and implicit parameter lists behaved exactly the same, but apparently not.
In the example below, I expect summon1[Int] and summon2[Int] to return the same type, but they don't. I expected summon2[Int] to return a path dependent type, but instead it gives me a type projection. Why?
Welcome to the Ammonite Repl 2.2.0 (Scala 2.13.3 Java 11.0.2)
# trait Foo[A] {
type B
def value: B
}
defined trait Foo
# implicit def fooInt = new Foo[Int] {
override type B = String
override def value = "Hey!"
}
defined function fooInt
# implicit def fooString = new Foo[String] {
override type B = Boolean
override def value = true
}
defined function fooString
# def summon1[T](implicit f: Foo[T]) = f.value
defined function summon1
# def summon2[T: Foo] = implicitly[Foo[T]].value
defined function summon2
# summon1[Int]
res5: String = "Hey!"
# summon2[Int]
res6: Foo[Int]#B = "Hey!"
#
The thing is primarily not in the difference of context bound vs. implicit parameter (there shouldn't be any difference (*)), the thing is that implicitly can break type of implicit found
https://typelevel.org/blog/2014/01/18/implicitly_existential.html
If you fix summon2 using custom materializer this will work as expected
def materializeFoo[T](implicit f: Foo[T]): Foo[T] { type B = f.B } = f
def summon2[T: Foo] = materializeFoo[T].value
summon2[Int]
// val res: String = Hey!
It's intersting that shapeless.the doesn't help
def summon2[T: Foo] = the[Foo[T]].value
summon2[Int]
// val res: Foo[Int]#B = Hey!
Also in Scala 2.13 you can use more general form of materializer (not specific for Foo) returning singleton type (like it's done in Scala 3)
def materialize[A](implicit f: A): f.type = f
def summon2[T: Foo] = materialize[Foo[T]].value
val y = summon2[Int]
// val res: String = Hey!
(*) Well, there is a difference that if you don't introduce parameter name f you can't refer to the type f.B explicitly in the return type. And if you don't specify return type explicitly, as we can see such type f.B can't be inferred because of the lack of a stable prefix f (see also Aux-pattern usage compiles without inferring an appropriate type).

Basic implicit query

I am new to Scala, and trying to get my head around implicit wizardry. I want to understand why I am getting 2mysize with + function and the 2 * the length for * function?
implicit def addToStr(str: String) = str.size
scala> 2 * "mysize"
res4: Int = 12
scala> 2 + "mysize"
res3: String = 2mysize
Have a look at the ScalaDocs page for the Int API. The Int class has a +() method for adding a String.
abstract def +(x: String): String
But it has no *() method for multiplying a String. The compiler will always choose a defined function/method over an implicit. It will only go looking for an implicit solution as a last resort.
Implicit Conversions are only applied if the expression doesn't match the argument type of the function.
Example:
import scala.language.implicitConversions
implicit def strToInt(s: String):Int = s.size
def printStr(s: Int):Unit = {
println(s"Printing Int ${s}")
}
printStr("SSSS")
In the above case, the implicit method comes into picture, but if you define another method as shown below.
def printStr(s: String) = {
println(s"Printing String ${s}")
}
It will automatically use this method rather than implicit resolutions.
https://www.scala-lang.org/old/node/3911.html

Making Typeclass Instance with `implicit def`?

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

passing a function with type parameter as argument

I want to create a function g that takes a function f as a parameter, where f has a type parameter. I can't get a signature for g that compiles. One attempt is like this:
scala> def mock1[A](): A = null.asInstanceOf[A] // STUB
mock1: [A]()A
scala> def mock2[A](): A = null.asInstanceOf[A] // STUB
mock2: [A]()A
scala> def g0(f: [A]() => A): Int = f[Int]()
<console>:1: error: identifier expected but '[' found.
def g0(f: [A]() => A): Int = f[Int]()
^
I can get it to work if I wrap the function that takes a type parameter in a trait, like so:
scala> trait FWrapper { def f[A](): A }
defined trait FWrapper
scala> class mock1wrapper extends FWrapper { def f[A]() = mock1[A]() }
defined class mock1wrapper
scala> class mock2wrapper extends FWrapper { def f[A]() = mock2[A]() }
defined class mock2wrapper
scala> def g(wrapper: FWrapper): Int = wrapper.f[Int]()
g: (wrapper: FWrapper)Int
scala> g(new mock1wrapper)
res8: Int = 0
Is there a way I can accomplish this without introducing the wrapper class?
Scala does (currently) not have support for polymorphic function values. You have two options:
Stick with your wrapper trait (probably easiest to understand)
Use polymorphic function values from Shapeless (fancy, but maybe a bit complicated)
How about this:
def mock[A](): A = null.asInstanceOf[A]
def g[A](f:() => A): A = f()
g(mock[Int])

What is the Scala identifier "implicitly"?

I have seen a function named implicitly used in Scala examples. What is it, and how is it used?
Example here:
scala> sealed trait Foo[T] { def apply(list : List[T]) : Unit }; object Foo {
| implicit def stringImpl = new Foo[String] {
| def apply(list : List[String]) = println("String")
| }
| implicit def intImpl = new Foo[Int] {
| def apply(list : List[Int]) = println("Int")
| }
| } ; def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x)
defined trait Foo
defined module Foo
foo: [A](x: List[A])(implicit evidence$1: Foo[A])Unit
scala> foo(1)
<console>:8: error: type mismatch;
found : Int(1)
required: List[?]
foo(1)
^
scala> foo(List(1,2,3))
Int
scala> foo(List("a","b","c"))
String
scala> foo(List(1.0))
<console>:8: error: could not find implicit value for evidence parameter of type
Foo[Double]
foo(List(1.0))
^
Note that we have to write implicitly[Foo[A]].apply(x) since the compiler thinks that implicitly[Foo[A]](x) means that we call implicitly with parameters.
Also see How to investigate objects/types/etc. from Scala REPL? and Where does Scala look for implicits?
implicitly is avaliable in Scala 2.8 and is defined in Predef as:
def implicitly[T](implicit e: T): T = e
It is commonly used to check if an implicit value of type T is available and return it if such is the case.
Simple example from retronym's presentation:
scala> implicit val a = "test" // define an implicit value of type String
a: java.lang.String = test
scala> val b = implicitly[String] // search for an implicit value of type String and assign it to b
b: String = test
scala> val c = implicitly[Int] // search for an implicit value of type Int and assign it to c
<console>:6: error: could not find implicit value for parameter e: Int
val c = implicitly[Int]
^
Here are a few reasons to use the delightfully simple method implicitly.
To understand/troubleshoot Implicit Views
An Implicit View can be triggered when the prefix of a selection (consider for example, the.prefix.selection(args) does not contain a member selection that is applicable to args (even after trying to convert args with Implicit Views). In this case, the compiler looks for implicit members, locally defined in the current or enclosing scopes, inherited, or imported, that are either Functions from the type of that the.prefix to a type with selection defined, or equivalent implicit methods.
scala> 1.min(2) // Int doesn't have min defined, where did that come from?
res21: Int = 1
scala> implicitly[Int => { def min(i: Int): Any }]
res22: (Int) => AnyRef{def min(i: Int): Any} = <function1>
scala> res22(1) //
res23: AnyRef{def min(i: Int): Int} = 1
scala> .getClass
res24: java.lang.Class[_] = class scala.runtime.RichInt
Implicit Views can also be triggered when an expression does not conform to the Expected Type, as below:
scala> 1: scala.runtime.RichInt
res25: scala.runtime.RichInt = 1
Here the compiler looks for this function:
scala> implicitly[Int => scala.runtime.RichInt]
res26: (Int) => scala.runtime.RichInt = <function1>
Accessing an Implicit Parameter Introduced by a Context Bound
Implicit parameters are arguably a more important feature of Scala than Implicit Views. They support the type class pattern. The standard library uses this in a few places -- see scala.Ordering and how it is used in SeqLike#sorted. Implicit Parameters are also used to pass Array manifests, and CanBuildFrom instances.
Scala 2.8 allows a shorthand syntax for implicit parameters, called Context Bounds. Briefly, a method with a type parameter A that requires an implicit parameter of type M[A]:
def foo[A](implicit ma: M[A])
can be rewritten as:
def foo[A: M]
But what's the point of passing the implicit parameter but not naming it? How can this be useful when implementing the method foo?
Often, the implicit parameter need not be referred to directly, it will be tunneled through as an implicit argument to another method that is called. If it is needed, you can still retain the terse method signature with the Context Bound, and call implicitly to materialize the value:
def foo[A: M] = {
val ma = implicitly[M[A]]
}
Passing a subset of implicit parameters explicitly
Suppose you are calling a method that pretty prints a person, using a type class based approach:
trait Show[T] { def show(t: T): String }
object Show {
implicit def IntShow: Show[Int] = new Show[Int] { def show(i: Int) = i.toString }
implicit def StringShow: Show[String] = new Show[String] { def show(s: String) = s }
def ShoutyStringShow: Show[String] = new Show[String] { def show(s: String) = s.toUpperCase }
}
case class Person(name: String, age: Int)
object Person {
implicit def PersonShow(implicit si: Show[Int], ss: Show[String]): Show[Person] = new Show[Person] {
def show(p: Person) = "Person(name=" + ss.show(p.name) + ", age=" + si.show(p.age) + ")"
}
}
val p = Person("bob", 25)
implicitly[Show[Person]].show(p)
What if we want to change the way that the name is output? We can explicitly call PersonShow, explicitly pass an alternative Show[String], but we want the compiler to pass the Show[Int].
Person.PersonShow(si = implicitly, ss = Show.ShoutyStringShow).show(p)
Starting Scala 3 implicitly has been replaced with improved summon which has the advantage of being able to return a more precise type than asked for
The summon method corresponds to implicitly in Scala 2. It is
precisely the same as the the method in Shapeless. The difference
between summon (or the) and implicitly is that summon can return a
more precise type than the type that was asked for.
For example given the following type
trait F[In]:
type Out
def f(v: Int): Out
given F[Int] with
type Out = String
def f(v: Int): String = v.toString
implicitly method would summon a term with erased type member Out
scala> implicitly[F[Int]]
val res5: F[Int] = given_F_Int$#7d0e5fbb
scala> implicitly[res5.Out =:= String]
1 |implicitly[res5.Out =:= String]
| ^
| Cannot prove that res5.Out =:= String.
scala> val x: res5.Out = ""
1 |val x: res5.Out = ""
| ^^
| Found: ("" : String)
| Required: res5.Out
In order to recover the type member we would have to refer to it explicitly which defeats the purpose of having the type member instead of type parameter
scala> implicitly[F[Int] { type Out = String }]
val res6: F[Int]{Out = String} = given_F_Int$#7d0e5fbb
scala> implicitly[res6.Out =:= String]
val res7: res6.Out =:= String = generalized constraint
However summon defined as
def summon[T](using inline x: T): x.type = x
does not suffer from this problem
scala> summon[F[Int]]
val res8: given_F_Int.type = given_F_Int$#7d0e5fbb
scala> summon[res8.Out =:= String]
val res9: String =:= String = generalized constraint
scala> val x: res8.Out = ""
val x: res8.Out = ""
where we see type member type Out = String did not get erased even though we only asked for F[Int] and not F[Int] { type Out = String }. This can prove particularly relevant when chaining dependently typed functions:
The type summoned by implicitly has no Out type member. For this
reason, we should avoid implicitly when working with dependently typed
functions.
A "teach you to fish" answer is to use the alphabetic member index currently available in the Scaladoc nightlies. The letters (and the #, for non-alphabetic names) at the top of the package / class pane are links to the index for member names beginning with that letter (across all classes). If you choose I, e.g., you'll find the implicitly entry with one occurrence, in Predef, which you can visit from the link there.