Implicit lifting in scala - 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>

Related

Mapping over generic tuples with polymorphic functions

Scala 3 provides polymorphic functions and Tuples similar to shapeless HList:
scala> 1 *: "foo" *: Tuple()
val res0: (Int, String) = (1,foo)
scala> val f: ([T] => T => Option[T]) = [T] => (v: T) => Some(v)
val f: PolyFunction{apply: [T](x$1: T): Option[T]} = <function1>
scala> res0.map(f)
val res1: Option[Int] *: Option[String] *: EmptyTuple = (Some(1),Some(foo))
How could we reimplement the following shapeless example using Scala 3 functionality?
import poly._
object choose extends (Set ~> Option) {
def apply[T](s : Set[T]) = s.headOption
}
scala> val sets = Set(1) :: Set("foo") :: HNil
sets: Set[Int] :: Set[String] :: HNil = Set(1) :: Set(foo) :: HNil
scala> val opts = sets map choose
opts: Option[Int] :: Option[String] :: HNil = Some(1) :: Some(foo) :: HNil
In other words, how could we make something like so compile
scala> val choose: ([T] => Set[T] => Option[T]) = [T] => (s: Set[T]) => s.headOption
val choose: PolyFunction{apply: [T](x$1: Set[T]): Option[T]} = <function1>
scala> val sets = Set(1) *: Set("foo") *: Tuple()
val sets: (Set[Int], Set[String]) = (Set(1),Set(foo))
scala> sets.map(choose)
1 |sets.map(choose)
| ^^^^^^
| Found: (choose : PolyFunction{apply: [T](x$1: Set[T]): Option[T]})
| Required: PolyFunction{apply: [t](x$1: t): Any}
Shapeless map is quite a bit more magical than Scala 3 tuple map, the signature of latter being:
def map[F[_]](f: [t] => (x$1: t) => F[t]): Map[Tuple, F]
Map[Tuple, F] is a special match type that is basically tuple with every argument type wrapped in F[_]. The issue is that shape, t => F[t] that prevents too much fanciness.
Except of course, F can be a match type itself:
type Choose[T] = T match {
case Set[a] => Option[a]
}
def choose[T](t: T): Choose[T] = t match
case set: Set[a] => set.headOption
// messy, but it works
#main def run =
val sets = Set(1) *: Set("foo") *: Tuple()
println(sets.map([T] => (t: T) => choose(t)))
There's currently an issue that compiler won't infer polymorphic function from methods. Match types aren't fully type-safe either, e.g. doing choose("string") will compile but throw a MatchError. I've also ran into problems with inference of a match type from polymorphic function value, hence the usage of def method.

Scala + Shapeless abstract over curried function

I'm trying to figure out how to abstract over a curried function.
I've can abstract over an uncurried function via:
def liftAU[F, P <: Product, L <: HList, R, A[_]](f: F)
(implicit
fp: FnToProduct.Aux[F, L => R],
gen: Generic.Aux[P, L],
ap: Applicative[A]
): A[P] => A[R] = p => p.map(gen.to).map(f.toProduct)
This will take a function like (Int, Int) => Int and turn it into something like Option[(Int, Int)] => Option[Int]. And it works for any arity of function.
I want to create the curried version which will take a function like Int => Int => Int and convert it to Option[Int] => Option[Int] => Option[Int].
It should also work for any arity of curried function.
Since FnToProduct only works on the first parameter list, it's not helpful here, I've also tried to write some recursive definitions at the typelevel, but I'm having issues defining the types.
Not really sure if its possible, but would love to know if others have tried anything like this.
Dmytro's answer doesn't actually work for me unless I change the instance names in one of the objects, and even then it doesn't work for a function like Int => Int => Int => Int, and I find working with Poly values really annoying, so instead of debugging the previous answer, I'm just going to write my own.
You can actually write this operation pretty nicely using a 100% Shapeless-free type class:
import cats.Applicative
trait LiftCurried[F[_], I, O] {
type Out
def apply(f: F[I => O]): F[I] => Out
}
object LiftCurried extends LowPriorityLiftCurried {
implicit def liftCurried1[F[_]: Applicative, I, I2, O2](implicit
lc: LiftCurried[F, I2, O2]
): Aux[F, I, I2 => O2, F[I2] => lc.Out] = new LiftCurried[F, I, I2 => O2] {
type Out = F[I2] => lc.Out
def apply(f: F[I => I2 => O2]): F[I] => F[I2] => lc.Out =
(Applicative[F].ap(f) _).andThen(lc(_))
}
}
trait LowPriorityLiftCurried {
type Aux[F[_], I, O, Out0] = LiftCurried[F, I, O] { type Out = Out0 }
implicit def liftCurried0[F[_]: Applicative, I, O]: Aux[F, I, O, F[O]] =
new LiftCurried[F, I, O] {
type Out = F[O]
def apply(f: F[I => O]): F[I] => F[O] = Applicative[F].ap(f) _
}
}
It's probably possible to make that a little cleaner but I find it reasonable readable as it is.
You might want to have something concrete like this:
def liftCurriedIntoOption[I, O](f: I => O)(implicit
lc: LiftCurried[Option, I, O]
): Option[I] => lc.Out = lc(Some(f))
And then we can demonstrate that it works with some functions like this:
val f: Int => Int => Int = x => y => x + y
val g: Int => Int => Int => Int = x => y => z => x + y * z
val h: Int => Int => Int => String => String = x => y => z => _ * (x + y * z)
And then:
scala> import cats.instances.option._
import cats.instances.option._
scala> val ff = liftCurriedIntoOption(f)
ff: Option[Int] => (Option[Int] => Option[Int]) = scala.Function1$$Lambda$1744/350671260#73d06630
scala> val gg = liftCurriedIntoOption(g)
gg: Option[Int] => (Option[Int] => (Option[Int] => Option[Int])) = scala.Function1$$Lambda$1744/350671260#2bb9b82c
scala> val hh = liftCurriedIntoOption(h)
hh: Option[Int] => (Option[Int] => (Option[Int] => (Option[String] => Option[String]))) = scala.Function1$$Lambda$1744/350671260#45eec9c6
We can also apply it a couple more times just for the hell of it:
scala> val hhhh = liftCurriedIntoOption(liftCurriedIntoOption(hh))
hhh: Option[Option[Option[Int]]] => (Option[Option[Option[Int]]] => (Option[Option[Option[Int]]] => (Option[Option[Option[String]]] => Option[Option[Option[String]]]))) = scala.Function1$$Lambda$1744/350671260#592593bd
So the types look okay, and for the values…
scala> ff(Some(1))(Some(2))
res0: Option[Int] = Some(3)
scala> ff(Some(1))(None)
res1: Option[Int] = None
scala> hh(Some(1))(None)(None)(None)
res2: Option[String] = None
scala> hh(Some(1))(Some(2))(Some(3))(Some("a"))
res3: Option[String] = Some(aaaaaaa)
…which I think is what you were aiming for.
You can define recursive Poly
object constNone extends Poly1 {
implicit def zeroCase[In]: Case.Aux[In, Option[Int]] = at(_ => None)
implicit def succCase[In, In1, Out](implicit
cse: Case.Aux[In, Out]): Case.Aux[In1, In => Out] = at(_ => cse(_))
}
object transform extends Poly1 {
implicit def zeroCase: Case.Aux[Int, Option[Int]] = at(Some(_))
implicit def succCase[In, Out](implicit
cse: Case.Aux[In, Out],
noneCase: constNone.Case.Aux[In, Out]
): Case.Aux[Int => In, Option[Int] => Out] =
at(f => {
case Some(n) => cse(f(n))
case None => noneCase(f(0))
})
}
(transform((x: Int) => (y: Int) => x + y) _)(Some(1))(Some(2)) //Some(3)
(transform((x: Int) => (y: Int) => x + y) _)(Some(1))(None) //None
(transform((x: Int) => (y: Int) => x + y) _)(None)(Some(2)) //None

Scala: Why foreach with a single argument function does not work with a zipped result

I have the following Scala program:
object Test extends App {
val zip = (List(1, 3, 5), List(2, 4, 6)).zipped
val f: Tuple2[Int, Int] => Unit = x => println(x._1 + x._2)
zip.foreach(f)
}
Why I get the following compiler error:
Error:(6, 15) type mismatch;
found : ((Int, Int)) => Unit
required: (Int, Int) => ?
zip.foreach(f)
when there is an implicit conversion from Tuple2Zipped to Traversable where foreach[U](f: ((El1, El2)) => U): Unit is defined.
NOTE: I edited my question to clarify.
I know that the foreach defined in Tuple2Zipped has the following signature:
def foreach[U](f: (El1, El2) => U): Unit
and that my function f does not fit as the argument.
But in Tuple2Zipped.scala is defined the trait ZippedTraversable2 and his companion object this way:
trait ZippedTraversable2[+El1, +El2] extends Any {
def foreach[U](f: (El1, El2) => U): Unit
}
object ZippedTraversable2 {
implicit def zippedTraversable2ToTraversable[El1, El2](zz: ZippedTraversable2[El1, El2]): Traversable[(El1, El2)] = {
new scala.collection.AbstractTraversable[(El1, El2)] {
def foreach[U](f: ((El1, El2)) => U): Unit = zz foreach Function.untupled(f)
}
}
}
so as my function f does match the argument of the foreach defined in the Traversable returned by zippedTraversable2ToTraversable and the companion object defines an implicit conversion from ZippedTraversable2 to this Traversable and Tuple2Zipped is a ZippedTraversable2, i think that this conversion has to be tried and my function be accepted.
The Intellij Idea editor accepts my construct without reporting any error but the compiler fails with the shown error.
Here is yet another, and slightly more esoteric, way to fix your code.
zip.foreach(Function.untupled(f))
Function.untupled() will take a ((Int, Int)) => Unit, which is what you've got in f, and return a (Int, Int) => Unit, which is what you need to process the zip elements.
Your function f is wrong ( it's also explicitly stated in the error )
zip.foreach expectes Function2 that takes type T1, type T2 and returns R, but you are passing a Function1 that takes Tuple2[Int,Int] as type T1
Here's an explaination regarding your compilation error :
found : ((Int, Int)) => Unit EQUALS Function1[Tuple2[Int,Int]] => Unit
Whereas
required: (Int, Int) => Unit EQUALS Function2[Int,Int,Unit]
(Keep in mind that () is syntactic sugar for Tuple* , that's why your are seeing the double parenthesis)
Here's an example that compiles :
val zip = (List(1, 3, 5), List(2, 4, 6)).zipped
val f:Function2[Int,Int,Unit] = (x,y) => println(x + y)
zip.foreach[Unit](f)
Your object is a runtime.Tuple2Zipped, if you look at the signature
def foreach[U](f: (El1, El2) => U): Unit
It takes a function f: (El1, E1l2) => U, but your function is f: ((El1, El2)) => U, hence the error.
I found it confusing too, as Tuple2Zipped almost looks like a List[(A,B)], in fact the toList method would produce just that:
val zip = (List(1, 3, 5), List(2, 4, 6)).zipped.toList
val f: Tuple2[Int, Int] => Unit = x => println(x._1 + x._2)
zip.foreach(f)
Edit
I think you are looking for an implicit conversion from ((A, B)) => U to (A, B) => U which is not what zippedTraversable2ToTraversable does. You can define something like this that would work:
implicit def tupconv[A,B] (f: (((A,B)) => Unit)): (A, B) => Unit = Function.untupled(f)
Edit V2
For the code above you'd need an implicit variable in scope that would map from ((A,B)) => Unit to (A, B) => Unit as that's where the mismatch is. Whereas the one you quoted does ZippedTraversable2[El1, El2] to Traversable[(El1, El2)]. If you'd like to make use of that implicit conversion, you could do this:
val zip = (List(1, 3, 5), List(2, 4, 6)).zipped
val f: Tuple2[Int, Int] => Unit = x => println(x._1 + x._2)
def thisUsesTheImplicitYouWant(t: Traversable[(Int,Int)]) = t.foreach(f)
thisUsesTheImplicitYouWant(zip)
Thanks to Jasper-M I have known that a Scala bug has been reported on this issue: https://github.com/scala/bug/issues/9523. This bug was reported by Michael Pollmeier that asked this question one and a half years ago: Why does Scala implicit resolution fail for overloaded method with type parameter?
jamborta posted a question with a more generic example on this same issue here.

Can I solve it with Shapeless?

Suppose I have a few functions:
val f1: Int => String
val f2: (Int, Int) => String
val f3: (Int, Int, Int) => String
def fromList1(f: Int => String): List[Int] => Option[String] =
_ match {case x::_ => Some(f(x)); case _ => None}
def fromList2(f: (Int, Int) => String): List[Int] => Option[String] =
_ match {case x::y::_ => Some(f(x, y)); case _ => None}
Now I would like to write one generic fromList to work as follows:
val g1: List[Int] => String = fromList(f1) // as fromList1(f1)
val g2: List[Int] => String = fromList(f2) // as fromList2(f2)
Can I do that with shapeless ?
This may help:
import shapeless._
import syntax.std.traversable._
import shapeless.ops.traversable._
import syntax.std.function._
import ops.function._
def fromList[F, L <: HList, R](f: F)
(implicit fp: FnToProduct.Aux[F, L => R], tr: FromTraversable[L]) =
(p: List[Int]) => p.toHList[L] map f.toProduct
f.toProduct transforms regular function to function that takes HList as parameter - it requires FnToProduct implicit and actually just call it. FnToProduct.Aux is constructor (generated by macro) that creates FnToProduct from dunction F, hlist type HList and result type R. All of them are inferred from f parameter you passed.
Last one, toHList creates Some(HList) from regular List if it's possible, otherwise - None. It uses FromTraversable[L] implicit to do that, where L is already inferred from f. Shapeless2 is smart enough to recognize HList from Tuple (as there probably is implicit conversion).
Example:
scala> val f1: Int => String = _ => "a"
f1: Int => String = <function1>
scala> val f2: (Int, Int) => String = (_, _) => "a"
f2: (Int, Int) => String = <function2>
scala> val g1 = fromList(f1)
g1: List[Int] => Option[String] = <function1>
scala> g1(List(1))
res6: Option[String] = Some(a)
scala> val g2 = fromList(f2)
g2: List[Int] => Option[String] = <function1>
scala> g2(List(1, 2))
res7: Option[String] = Some(a)
scala> g2(List(1))
res8: Option[String] = None
Yes you can
import shapeless._
import shapeless.ops.traversable._
import syntax.std.traversable._
import ops.function._
def fromList[F, I <: HList, O](f: F)(implicit
ftp: FnToProduct.Aux[F, I => O],
ft: shapeless.ops.traversable.FromTraversable[I]): List[Int] => Option[O] =
{ x: List[Int] => x.toHList[I].map(ftp(f)) }
Explanation
We're using FnToProduct to transform any FunctionN to a Function1 that takes an HList as only argument.
So,
Int => String ----> Int :: HNil => String
(Int, Int) => String ----> Int :: Int :: HNil => String
...
Now that we abstracted over the arity of the input parameters for the function, we can simply convert the List[Int] to an HList that suits the transformed function's input.
In order to perform this conversion we need to a FromTraversable[I] in scope.
If everything succeeds we return and Option[O] where O is the return type of the function.
If the input List has the wrong shape, we simply fail returning None.
Usage
# val f1: Int => String = _.toString
f1: Int => String = <function1>
# val f2: (Int, Int) => String = (_, _).toString
f2: (Int, Int) => String = <function2>
# val fromList1 = fromList(f1)
fromList1: List[Int] => Option[String] = <function1>
# val fromList2 = fromList(f2)
fromList2: List[Int] => Option[String] = <function1>
# fromList1(List(1))
res22: Option[String] = Some(1)
# fromList2(List(1, 2))
res23: Option[String] = Some((1,2))
# fromList1(List())
res24: Option[String] = None

Using implicit def with composed types

Forgive me if this question is a duplicate; I'm having trouble finding anything because I don't know the right words to search. So, with implicit def, I can do things like this:
type CharsetMap = Map[Charset, Byte]
implicit def seqtup2CharsetMap(input: Seq[(String, Int)]): CharsetMap = {
Map.empty // placeholder
}
def somef(a: Int, b:Int, p: CharsetMap) = p
somef(1, 3, Seq(("hey", 2), ("there", 9)))
which lets me call somef with a Seq[(String, Int)] object as a parameter. The problem is that I have something like this...
def somef2(p: (CharsetMap) => Int) = p
and this does not work:
val p = (a: Seq[(String, Int)]) => 19
somef2(p)
How can I do this without doing an implicit def specifically for (Seq[(String, Int)]) => Int?
It looks like you want to implicitly convert some function A => B to a function that goes from C => B. You can do that with this generic implicit:
implicit def f2InputConverter[A, B, C](f: A => B)(implicit i: C => A): C => B = (c: C) => f(i(c))
Once you have that in scope, in your particular case, you'll need an implicit function which is the inverse of the one that you've defined in the question:
implicit def charsetMap2Seqtup(input: CharsetMap): Seq[(String, Int)] = {
Nil // placeholder
}
and then you should be able to call somef2 with p