2015-02-11 134 views
8

我只是碰到了功能和对象之间的差距怪(斯卡拉2.10):Scala中defs/lambdas的隐式转换?

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 

为什么会出现DEFS /λ文字和λ丘壑之间的差异?

更新:显然,问题不为二元函数发生:Implicit conversion of a function to a second-order-function only works if the function to convert has at least two parameters

我检查这个,乃至下面的代码工作:

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 

同样的,无参函数不构成问题,要么:

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 

所以,改写的问题:为什么这不适用于UNARY方法和函数?

更新:问题似乎也与目标类型(f的参数类型h)有关。下面也可以(这个时候,有利于“埃塔膨胀算作跳”,因为我们需要从使用_创建方法值)

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 
+1

m aybe scalac认为defs/lambda文字转换为FunctionN已经是一个隐式跳转(最多允许一个跳转)? – 2015-02-11 13:02:01

+0

刚刚检查了规格。 Eta扩展应该是免费的,所以三者应该相当于w.r.t.查看应用程序:“我们说,如果T在应用eta-expansion *和* view应用程序后T弱地符合U,则类型T与U型兼容。” – 2015-02-11 16:07:30

+0

http://stackoverflow.com/questions/28456012/implicit-conversion-of-a-function-to-a-second-order-function-only-works-if-the-f – 2015-02-12 02:21:49

回答

3

斯卡拉defsmethods和来自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> 

您可以通过局部应用它转换methodfunction

scala> b _ 
res1: (Int, Int) => Int = <function2> 

所以..你可以做,

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,如@ srgfed01在他的评论中提到...对于第二种情况,问题是......他们类型没有明确规定,如果您正确指定类型...第二种情况将起作用。

scala> f((a => a.toString): (Int => String)) 
1 

scala> f((_.toString): (Int => String)) 
1 

现在,关于methodsfunctions之间的差异...

你可以调用method不带参数没有括号() ...但你不能调用功能没有()

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 

其中一个最重要的原因是methodsfunctions不同的是,因为Scala的创建者希望与Java的无缝间的互操作性,而不被卡住Java的限制。

所以methodsdef)都非常类似于Java methods并保持functions不同methods有无限的自由创造斯卡拉,他们想要的方式使他们。

另外...另一个主要区别是,methods可以接受Type-classesfunctions不能。基本上,你可以有通用methods

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 

现在,您可以定义一个通用的方法,

scala> def check[ T <: Behave ](t: T): Unit = t.behave() 
check: [T <: Behave](t: T)Unit 

但你不能这样定义一个函数,

scala> (t: T) => t.behave() 
<console>:8: error: not found: type T 
      (t: T) => t.behave() 

或类似这样的

scala> (t: (T <: Behave)) => t.behave() 
<console>:1: error: ')' expected but '<:' found. 
    (t: (T <: A)) => t.behave() 
+0

错误也可以通过定义参数类型显式:第一种情况 - 'f(a:Int => String)'和第二种 - 'f((_ _ toString):Int => String)'。 – user5102379 2015-02-11 13:41:43

+0

我认为这里的“修复方法类型”实际上是一个显式的函数转换,所以如果eta-expansion随后是视图应用程序,或者它被视为隐式转换它自己的权利。 – 2015-02-11 16:21:15

+0

你在哪里看到“修复方法类型”? – 2015-02-11 16:33:02