Implicit conversion of a function to a second-order-function only works if the function to convert has at least two parameters

。_饼干妹妹 提交于 2019-12-21 12:12:53

问题


I have a problem of implicit conversions and higher-order functions. It seems that an implicit conversions of a function to a second-order-function only works, if the function to convert has at least two parameters.

Works:

implicit def conv(foo: Integer => String): String => String = null

Does not work:

implicit def conv(foo: Integer => String): String => String => String = null

Works:

implicit def conv(foo: (Integer, Integer) => String): String => String => String = null

Full example with point of failure:

{
    implicit def conv(foo: Integer => String): String => String = null

    def baadf00d(foo: Integer): String = null

    def deadbeef(foo: String => String) = null

    deadbeef(conv(baadf00d))

    deadbeef(baadf00d)
}

{
    implicit def conv(foo: Integer => String): String => String => String = null

    def baadf00d(foo: Integer): String = null

    def deadbeef(foo: String => String => String) = null

    deadbeef(conv(baadf00d))

    deadbeef(baadf00d) // <-------- DOES NOT COMPILE!
}

{
    implicit def conv(foo: (Integer, Integer) => String): String => String => String = null

    def baadf00d(foo: Integer, bar: Integer): String = null

    def deadbeef(foo: String => String => String) = null

    deadbeef(conv(baadf00d))

    deadbeef(baadf00d)
}

What am I missing?

Thanks!


回答1:


  implicit def conv(foo: Integer => String): String => String => String = ???

  def baadf00d(i: Integer): String = ???
  def goodf00d: Integer => String = _ => ???

  def deadbeef(foo: String => String => String) = ???

  deadbeef(conv(baadf00d))

  deadbeef(baadf00d) // <-------- DOES NOT COMPILE!
  deadbeef(goodf00d) // <-------- COMPILE!
  // ¯\_(ツ)_/¯

The issue is how implicit conversions work on Scala and the fact that there are curried and uncurried functions in Scala.

This is something that SHOULD work but doesn't and is probably just yet another compiler bug (get ready to meet many more as you use Scala more and more).

EDIT: As for your last example

implicit def conv(foo: (Integer, Integer) => String): String => String => String = null

def baadf00d(foo: Integer, bar: Integer): String = null

def deadbeef(foo: String => String => String) = null

That's because there the function definitions do match. The conv expects a function (Int, Int) => String and a normal method definition (uncurried) in scala, like how baadf00d is defined, turns into that.

For example, a function:

def f(a: Int, b: Int): String

Gets turned into a

(Int, Int) => String

Notice that the 2 Ints are tupled! This is NOT the same as:

Int => Int => String

If you were to redefine baadf00d into:

def baadf00d: Integer => Integer => String = _ => _ => ???

That code won't compile, because baadf00d is now "different", even though it is doing the same thing.

For more information, look at the definition of the objects:

Function1, Function2, Function3 ....

http://www.scala-lang.org/api/current/#scala.Function2




回答2:


implicit def conv1(a: Function1[Int, String]): Function2[String, String, String] = null
def baadf00d1(i: Int): String = null
def deadbeef1(arg: Function2[String, String, String]) = null  
deadbeef(baadf00d) // compiles

It's the conversion between A => B and Function1[A,B] that isn't happening.

Also there is a Function type in Predef -- notice the type differences here:

scala> val f1: Function[Int, Int] = null
f1: Function[Int,Int] = null

scala> val f2: Function1[Int, Int] = null
f2: Int => Int = null

scala> :type f1
Function[Int,Int]

scala> :type f2
Int => Int

It's an alias to Function1, but with different type bounds (as pointed out in the comments below).



来源:https://stackoverflow.com/questions/28456012/implicit-conversion-of-a-function-to-a-second-order-function-only-works-if-the-f

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!