2015-02-11 5 views
8

Я просто побежал в странное несоответствие между функциями и объектами (2.10) Scala:Неявные преобразования для defs/lambdas в Scala?

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/лямбда-литералов и лямбда вальса?

Update: видимо, проблема не возникает для бинарных функций: 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). Далее работает (на этот раз, в пользу «рассчитывает ETA-расширение, как прыжок», потому что нам нужно создать значение методы из использования _)

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 уже неявным прыжком (из которого разрешено не более одного)? –

+0

Просто проверил спецификации. Eta-расширение должно появиться бесплатно, поэтому три должны быть эквивалентными w.r.t. view: «Мы говорим, что тип T совместим с типом U, если T слабо соответствует U после применения приложений eta-expand * и * view». –

+0

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

ответ

3

В Скале defs является methods и diffrent от 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> 

Вы можете преобразовать method в function путем частичного его применения.

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 

Теперь о различиях между methods и functions ...

Вы можете назвать 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 

Одним из наиболее важных причин для methods, отличающимися от functions потому, что создатели Scala хотели бесшовные интер-совместимости с Java без застревания с ограничениями Java.

Так methods (def) очень сильно похожи на Java methods и сохраняя functions отличающиеся от methods позволил им с безграничной свободой создания Scala, как они хотели.

Также ...Другое существенное отличие состоит в том, что methods может принимать Type-classes, где functions не может. В принципе вы можете иметь общий 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

+0

Я бы подумал, что «исправление типа метода» здесь на самом деле является явным преобразованием в функцию, поэтому мы вернемся к вопросу, если это расширение будет доступно бесплатно, если появится приложение просмотра, или если оно считается неявным преобразованием в свое право. –

+0

Где вы видите «фиксацию типа метода»? –

Смежные вопросы