Implicit conversion is not applied if a method has type parameter - scala

The question is based on the discussion here. This is the setup:
implicit def CToC2(obj: C1): C2 = {
new C2()
}
class C1() {
def f[U](f: (Int, Int) => U): U = f(1, 1)
}
class C2() {
def f[U](f: ((Int, Int)) => U): U = f(2, 2)
}
I'd expect that trying to call the function with a signature that exists in C2, scala would use the implicit conversion to satisfy the call:
val c1 = new C1()
val ff: ((Int, Int)) => Unit = t => println(t._1 + t._2)
But this fails:
scala> c1.f(ff)
Error:(16, 7) type mismatch;
found : ((Int, Int)) => Unit
required: (Int, Int) => ?
Interestingly if I drop the type parameter from C1, it works fine:
class C1() {
def f(f: (Int, Int) => Unit): Unit = f(1, 1)
}

Related

How to flat nest tuple parameter in function?

I have a function g which need parameter (Int, (Int, Int)) => Int, and a flat function f0 (Int, Int, Int) => Int
I want to construct a function ft which can flat parameters of g to f0.
Here is the example:
val f0: ((Int, Int, Int)) => Int = (x: (Int, Int, Int)) => {
x._1 + x._2 + x._3
}
def g(f: ((Int, (Int, Int))) => Int): Int = f(1,(2,3))
def ft(f: ((Int, Int, Int)) => Int): ((Int, (Int, Int))) => Int = (p: (Int, (Int, Int))) => {
f(p._1, p._2._1, p._2._2)
}
// invoke it
g(ft(f0))
But I have several functions of nested tuples, and I don't want to transform each manually. For example, ((Int, Int), (Int, Int)) => Int to (Int, Int, Int, Int) => Int
Here said it could use shapeless
Then the new function would like
import shapeless._
import ops.tuple.FlatMapper
trait LowPriorityFlatten extends Poly1 {
implicit def default[T] = at[T](Tuple1(_))
}
object flatten extends LowPriorityFlatten {
implicit def caseTuple[P <: Product](implicit lfm: Lazy[FlatMapper[P, flatten.type]]) =
at[P](lfm.value(_))
}
def ft(f: ((Int, Int, Int)) => Int): ((Int, (Int, Int))) => Int = (p: (Int, (Int, Int))) => {
val a: (Int, Int, Int) = flatten(p).asInstanceOf[(Int, Int, Int)]
f(a)
}
Code above has two problem:
how to define function ft[A, B, C](f: A => C): B where A is a flatten type of B ?
flatten(p) will product type FlatMapper.this.Out and miss the type, so I use asInstanceOf to cast type here.
So, How to write a function to flatten any kind of nested tuple in a parameter?
The following code works in Scala 3:
scala> type Flat[T <: Tuple] <: Tuple = T match
| case EmptyTuple => EmptyTuple
| case h *: t => h match
| case Tuple => Tuple.Concat[Flat[h], Flat[t]]
| case _ => h *: Flat[t]
|
scala> def flat[T <: Tuple](v: T): Flat[T] = (v match
| case e: EmptyTuple => e
| case h *: ts => h match
| case t: Tuple => flat(t) ++ flat(ts)
| case _ => h *: flat(ts)).asInstanceOf[Flat[T]]
def flat[T <: Tuple](v: T): Flat[T]
scala> def ft[A <: Tuple, C](f: Flat[A] => C): A => C = a => f(flat(a))
def ft[A <: Tuple, C](f: Flat[A] => C): A => C
scala> val f0: ((Int, Int, Int)) => Int = x => x._1 + x._2 + x._3
scala> def g0(f: ((Int, (Int, Int))) => Int): Int = f(1,(2,3))
scala> g0(ft(f0))
val res0: Int = 6
Edit: Add scala2's version:
import shapeless._
import ops.tuple.FlatMapper
import syntax.std.tuple._
trait LowPriorityFlat extends Poly1 {
implicit def default[T] = at[T](Tuple1(_))
}
object Flat extends LowPriorityFlat {
implicit def caseTuple[P <: Product](implicit fm: FlatMapper[P, Flat.type]) =
at[P](_.flatMap(Flat))
}
type F[A, B] = FlatMapper.Aux[A, Flat.type, B]
def flatTup[T <: Product](t: T)(implicit lfm: FlatMapper[T, Flat.type]): lfm.Out =
FlatMapper[T, Flat.type].apply(t)
def flatFun[A <: Product, B <: Product, C](f: B => C)
(implicit lfm: F[A, B]): A => C =
a => f(flatTup(a))
val f0: ((Int, Double, Int, Double)) => Double = { case(i1, d1, i2, d2) => (i1 + i2) / (d1 + d2) }
def g0(f: (((Int, Double), (Int, Double))) => Double): Double = f((1, 2.0), (3, 4.0))
val r0 = g0(flatFun(f0))

Why is this implicit function not being applied?

Trying out the implicit conversion of TupleN proposed by #Alexey Romanov in How to apply implicit conversions between tuples?
Given the following implicits:
object ImplicitConversions {
object A {
implicit def toA(x: Int): A = A(x)
}
case class A(v: Int) extends AnyVal
implicit def liftImplicitTuple2[A, B, A1, B1](tuple: (A, B))
(implicit f1: A => A1, f2: B => B1): (A1, B1) =
(f1(tuple._1), f2(tuple._2))
}
and the Tuple (1,2), I can manually apply liftImplicitTuple2 and have it invoke the A implicit conversion:
import ImplicitConversions._
val x = (1, 2)
val y: (A, Int) = liftImplicitTuple2(x)
However, if I just try to have x converted to y, such that:
import ImplicitConversions._
val x = (1, 2)
val y2: (A, Int) = x
I get:
Error:(12, 22) type mismatch;
found : (Int, Int)
required: (sandbox.ImplicitConversions.A, Int)
val y2: (A, Int) = x
Is there some other import I need to get liftImplicitTuple2 into scope as an implicit?

How to compose tupled unary functions by combining their input tuples

I've been playing around with shapeless for a bit now.
But, yesterday I got stuck when trying to compose tupled functions.
What I was looking into specifically is composing two unary functions f1: T => R and f2: R => U => S into f: TU => S where T is a TupleN and TU := (t1, ... , tn, u)
import shapeless.ops.tuple._
implicit class Composable[T <: Product, R](val f1: T => R) extends AnyVal{
def compose2[U, S](f2: R => U => S)(implicit p: Prepend[T, Tuple1[U]]): (p.Out => S) = {
// how to provide the two required implicits for Last[p.Out] and Init[p.Out]?
tu => f1.andThen(f2)(tu.init)(tu.last)
}
}
val f1: ((Int, Int)) => Int = x => x._1 * x._2
val f2: ((Int, Int, Int)) => Int = f1.compose2((y: Int) => (x3: Int) => x3 + y).apply _
What I've been struggling with is providing the implicit proof for the tuple operations last and init, so the above code won't compile!
From a logical perspective it feels trivial as result of Prepend, but I couldn't figure out a way. So any idea is welcome :)
Using shapeless's facilities to abstract over arity I got somehow closer:
import shapeless.ops.function.{FnFromProduct, FnToProduct}
import shapeless.{::, HList}
implicit class Composable[F](val f: F) extends AnyVal{
// the new param U is appended upfront
def compose2[I <: HList, R, U, S](f2: R => U => S)
(implicit ftp: FnToProduct.Aux[F, I => R], ffp: FnFromProduct[U :: I => S]): ffp.Out = {
ffp(list => f2.compose(ftp(f))(list.tail)(list.head))
}
}
val f1: (Int, Int) => Int = (x1,x2) => x1 * x2
val f2: (Int, Int, Int) => Int = f1.compose2((y: Int) => (x3: Int) => x3 + y).apply _
This works, but then again I was really looking for compose2 to work on unary tupled Function1s. Also, this results in f: (U, t1, ..., tn) => S rather than f: TU => S with TU := (t1, ... , tn, u).
As Miles says, this would be more convenient with an undo for Prepend, but since the length of the second part is fixed, an approach similar to the one in my other answer isn't too bad at all:
import shapeless.ops.tuple._
implicit class Composable[T <: Product, R](val f1: T => R) extends AnyVal {
def compose2[U, S, TU](f2: R => U => S)(implicit
p: Prepend.Aux[T, Tuple1[U], TU],
i: Init.Aux[TU, T],
l: Last.Aux[TU, U]
): (p.Out => S) =
tu => f1.andThen(f2)(i(tu))(l(tu))
}
And then:
scala> val f1: ((Int, Int)) => Int = x => x._1 * x._2
f1: ((Int, Int)) => Int = <function1>
scala> val f2: ((Int, Int, Int)) => Int =
| f1.compose2((y: Int) => (x3: Int) => x3 + y).apply _
f2: ((Int, Int, Int)) => Int = <function1>
scala> f2((2, 3, 4))
res1: Int = 10
The trick is adding the output of Prepend to the type parameter list for compose2—which will generally be inferred—and then using Prepend.Aux to make sure that it's inferred appropriately. You'll often find in Shapeless that you need to refer to the output type of a type class in other type class instances in the same implicit parameter list in this way, and the Aux type members make doing so a little more convenient.

Implicit conversions for defs/lambdas in Scala?

I just ran into a strange disparity between functions and objects (scala 2.10):
implicit def conv(c: Int => String) : (PrintStream => Int => Unit) = p => v => p.println(c(v))
def f(h: PrintStream => Int => Unit) : Unit = h(System.out)(1)
def a(x: Int) = x.toString
val b = (x: Int) => x.toString
// def main(args: Array[String]) = f(a) // fail
// def main(args: Array[String]) = f((x: Int) => x.toString) // fail
def main(args: Array[String]) = f(b) // ok
Why is there a difference between defs/lambda literals and lambda vals?
Update: apparently, the Problem does not occur for binary functions: Implicit conversion of a function to a second-order-function only works if the function to convert has at least two parameters
I checked this, and indeed the following code works:
implicit def conv(c: (Int,Unit) => String) : (PrintStream => Int => Unit) = p => v => p.println(c(v,()))
def f(h: PrintStream => Int => Unit) : Unit = h(System.out)(1)
def a(x: Int, y : Unit) = x.toString
val b = (x: Int, y : Unit) => x.toString
def main(args: Array[String]) = f(a) // ok
def main(args: Array[String]) = f((x: Int, y: Unit) => x.toString) // ok
def main(args: Array[String]) = f(b) // ok
Likewise, Nullary functions don't pose a problem, either:
implicit def conv(c: () => String) : (PrintStream => Int => Unit) = p => v => p.println(c())
def f(h: PrintStream => Int => Unit) : Unit = h(System.out)(1)
def a() = "1"
val b = () => "1"
def main(args: Array[String]) = f(a) // ok
def main(args: Array[String]) = f(() => "1") // ok
def main(args: Array[String]) = f(b) // ok
So, rephrasing the question: why does this not work for UNARY methods and functions?
Update: the problem also seems to be related to the target type (the type of f's argument h). The following also works (this time, in favour of "eta-expansion counts as hop", because we need to create a method value from a using _)
implicit def conv(c: Int => String) : Unit = ()
def f(h: Unit) : Unit = System.out.print("?")
def a(x: Int) = x.toString
val b = (x: Int) => x.toString
def main(args: Array[String]) = f(a _) // ok
def main(args: Array[String]) = f((x: Int) => x.toString) // ok
def main(args: Array[String]) = f(b) // ok
In scala defs are methods and are diffrent from functions.
scala> def a( x: Int, y: Int ): Int = x + y
a: (x: Int, y:Int)Int
scala> (x: Int, y: Int) => x + y
res0: (Int, Int) => Int = <function2>
You can convert a method to function by partially applying it.
scala> b _
res1: (Int, Int) => Int = <function2>
So.. you can do,
implicit def conv(c: Int => String) : (PrintStream => Int => Unit) = p => v => p.println(c(v))
def f(h: PrintStream => Int => Unit) : Unit = h(System.out)(1)
def a(x: Int) = x.toString
val af = a _
def main( args: Array[ String ] ) = f( af )
Alse, as #srgfed01 mentioned in his comment... for the second case the problem is that... they types are not explicitly specified, if you specify the type correctly... the second case will work.
scala> f( ( a => a.toString ): (Int => String) )
1
or
scala> f( ( _.toString ): (Int => String) )
1
Now, about differences between methods and functions...
You can call a method taking no arguments without parenthesis ()... but you can not call a function without ().
scala> def g() = 5
g: ()Int
scala> g
res15: Int = 5
scala> () => 5
res13: () => Int = <function0>
scala> res13
res14: () => Int = <function0>
scala> res13()
res15: 5
One of the most important reasons for methods being different from functions is because creators of Scala wanted seamless inter-interoperability with Java without being stuck with Java's limitations.
So methods (def) are very much similar to Java methods and keeping functions different from methods enabled them with limitless freedom to create Scala, the way they wanted.
Also... Another major difference is that methods can accept Type-classes where as functions can not. Basically you can have generic methods like
scala> :paste
trait Behave {
def behave
}
class A( elem: String ) extends Behave {
def behave() {
println( elem )
}
}
// Exiting paste mode, now interpreting.
defined trait Behave
defined class A
Now you can define a generic method,
scala> def check[ T <: Behave ]( t: T ): Unit = t.behave()
check: [T <: Behave](t: T)Unit
But you can not define a function like this,
scala> ( t: T ) => t.behave()
<console>:8: error: not found: type T
( t: T ) => t.behave()
or like this
scala> ( t: (T <: Behave) ) => t.behave()
<console>:1: error: ')' expected but '<:' found.
( t: (T <: A) ) => t.behave()

Implicit lifting in scala

I want to implicitly convert functions from A => B to List[A] => List[B].
I wrote the following implicit definition:
implicit def lift[A, B](f: A => B): List[A] => List[B] = ...
Unfortunately, when I write the following code, implicit aren't applied:
val plusOne: (List[Int]) => List[Int] = (x: Int) => (x + 1)
If I annotate the function with explicit time, it works fine.
Why? How can I fix it?
UPDATE. It seems that the problem is specific to anonymous functions. Compare:
#Test
def localLiftingGenerics {
implicit def anyPairToList[X, Y](x: (X, Y)): List[X] => List[Y] = throw new UnsupportedOperationException
val v: List[String] => List[Int] = ("abc", 239)
}
#Test
def localLiftingFuns {
implicit def fun2ListFun[X, Y](f: X => Y): List[X] => List[Y] = throw new UnsupportedOperationException
val v: List[String] => List[Int] = ((x: String) => x.length)
}
The first one is compiled well. The second one is marked as error
According to The Scala Language Specification / Expressions / Anonymous Functions (6.23):
If the expected type of the anonymous function is of the form
scala.Functionn[S1, …, Sn, R], the expected type of e is R ...
So, the result type of the function will be inferred as List[Int] unless you separate the function definition from the function value assignment (to get rid of the expected type):
val function = (x: Int) => (x + 1)
val plusOne: (List[Int]) => List[Int] = function
or specify the function type explicitly:
val plusOne: (List[Int]) => List[Int] = ((x: Int) => (x + 1)): Int => Int
(Scala 2.9.1-1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_05)
A first observation: If you duplicate fun2ListFun and rename it to, e.g.,``fun2ListFun, you'll get
found : String => <error>
required: List[String] => List[Int]
Note that implicit conversions are not applicable because they are ambiguous:
both method fun2ListFun2 of type [X, Y](f: X => Y)List[X] => List[Y]
and method fun2ListFun of type [X, Y](f: X => Y)List[X] => List[Y]
are possible conversion functions from String => <error> to List[String] => List[Int]
val v: List[String] => List[Int] = ((x: String) => x.length)
It looks as if the compiler considers both implicits as applicable.
A second observation:
Splitting
val v: List[String] => List[Int] = ((x: String) => x.length) /* Error*/
into
val f = ((x: String) => x.length)
val v: List[String] => List[Int] = f /* Works */
makes the compiler happy.
The implicit conversion for the input value compiles. So we just have a problem for the output of the anonymous function
def localLiftingFuns {
implicit def fun2ListFun[X, Y](f: X => Y): List[X] => Y = throw new UnsupportedOperationException
val v: List[String] => Int = ((x: String) => x.length)
}
A possible fix using a second implicit conversion:
def localLiftingFuns {
implicit def fun2ListFun[X, Y](f: X => List[Y]): List[X] => List[Y] = throw new UnsupportedOperationException
implicit def type2ListType[X](x:X): List[X] = throw new UnsupportedOperationException
val v: List[String] => List[Int] = ((x: String) => x.length)
}
This version compiles.
Seems the compiler has hard time figuring what is going on with the type of the function. If you will give him a little help, it would work:
scala> implicit def lift[A,B](f: A => B) = (_:List[A]).map(f)
lift: [A, B](f: (A) => B)(List[A]) => List[B]
scala> val f: List[Int] => List[Int] = ((_:Int) + 1):(Int => Int)
f: (List[Int]) => List[Int] = <function1>