2015-02-11 18 views
8

Tôi chỉ chạy vào một chênh lệch kỳ lạ giữa chức năng và các đối tượng (scala 2.10):Chuyển đổi ngầm định cho defs/lambdas trong 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 

Tại sao lại có một sự khác biệt giữa defs/literals lambda và Vals lambda?

Cập nhật: rõ ràng, các vấn đề không xảy ra cho các chức năng nhị phân: Implicit conversion of a function to a second-order-function only works if the function to convert has at least two parameters

Tôi đã kiểm tra này, và thực sự đoạn mã sau hoạt động:

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 

Tương tự như vậy, chức năng Nullary không đặt ra một vấn đề , hoặc:

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 

Vì vậy, hãy nói lại câu hỏi: tại sao điều này không hoạt động cho các phương pháp và chức năng UNARY?

Cập nhật: vấn đề cũng dường như có liên quan đến loại mục tiêu (loại đối số f). Sau đây cũng làm việc (thời gian này, ủng hộ việc "đếm eta-mở rộng như hop", bởi vì chúng ta cần phải tạo ra một giá trị phương pháp từ một sử dụng _)

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 xem xét chuyển đổi của defs/lambda literals thành FunctionN đã là một hop ngầm (trong đó nhiều nhất là một được phép)? –

+0

Chỉ cần kiểm tra thông số kỹ thuật. Eta-mở rộng nên đến miễn phí, vì vậy ba nên tương đương với w.r.t. xem ứng dụng: "Chúng tôi nói, loại T tương thích với loại U nếu T yếu phù hợp với U sau khi áp dụng các ứng dụng xem và mở rộng eta *." –

+0

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

Trả lời

3

Trong scala defsmethods và là khác nhau từ 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> 

Bạn có thể chuyển đổi một method-function bởi một phần áp dụng nó.

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

Vì vậy .. bạn có thể làm,

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, như @ srgfed01 nêu trong bình luận của mình ... đối với trường hợp thứ hai vấn đề là ... loại họ không được chỉ định một cách rõ ràng , nếu bạn chỉ định đúng loại ... trường hợp thứ hai sẽ hoạt động.

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

hoặc

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

Bây giờ, về sự khác biệt giữa methodsfunctions ...

Bạn có thể gọi một method dùng không có đối số mà không cần ngoặc () ... nhưng bạn không thể gọi một chức năng không có ().

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 

Một trong những lý do quan trọng nhất đối với methods là khác nhau từ functions là vì người sáng tạo của Scala muốn liền mạch giữa các khả năng tương tác với Java mà không bị mắc kẹt với những hạn chế của Java.

Vì vậy methods (def) rất nhiều tương tự như Java methods và giữ functions khác nhau từ methods cho phép họ tự do vô hạn để tạo ra Scala, theo cách mà họ muốn.

Ngoài ra ...Một khác biệt lớn là methods có thể chấp nhận Type-classes trong đó không thể functions. Về cơ bản bạn có thể có chung methods như

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 

Bây giờ bạn có thể định nghĩa một phương pháp chung chung,

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

Nhưng bạn không thể định nghĩa một hàm như thế này,

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

hay như thế này

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

Lỗi cũng có thể được sửa bằng cách xác định các kiểu đối số một cách rõ ràng: đối với trường hợp đầu tiên - 'f (a: Int => String)' và thứ hai - 'f ((_. toString): Int => String)'. – user5102379

+0

Tôi nghĩ "sửa chữa loại phương thức" ở đây thực sự là chuyển đổi rõ ràng thành hàm, vì vậy chúng tôi sẽ trả lời câu hỏi nếu mở rộng eta miễn phí khi được theo dõi bởi ứng dụng xem hoặc nếu được tính là chuyển đổi ngầm Quyền riêng của nó. –

+0

Bạn đã thấy "sửa loại phương thức" ở đâu? –

Các vấn đề liên quan