2012-07-11 28 views
5

Tôi muốn chuyển đổi hoàn toàn các chức năng từ A => B sang List[A] => List[B].Ngắt nâng trong scala

tôi đã viết định nghĩa ngầm sau:

implicit def lift[A, B](f: A => B): List[A] => List[B] = ... 

Thật không may, khi tôi viết đoạn code sau, tiềm ẩn không được áp dụng:

val plusOne: (List[Int]) => List[Int] = (x: Int) => (x + 1) 

Nếu tôi chú thích các chức năng theo thời gian rõ ràng, nó hoạt động tốt.

Tại sao? Làm thế nào tôi có thể sửa chữa nó?

CẬP NHẬT. Dường như vấn đề là cụ thể đối với các hàm ẩn danh. So sánh:

@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) 
} 

Phương án đầu tiên được biên dịch tốt. Điều thứ hai được đánh dấu là lỗi

+0

Bạn có thể cung cấp mã bạn sử dụng để triển khai 'deficit def' không? –

+1

@ChrisJamesC Được cập nhật với một trường hợp kiểm tra –

+2

Bạn có chắc chắn bạn cần/muốn thực hiện việc này không? 'map' mua rất rõ ràng cho một vài ký tự và ví dụ: 'val plusOne: (List [Int]) => List [Int] = _ map (_ + 1)' thực sự ngắn hơn phiên bản của bạn. –

Trả lời

6

Theo The Scala Language Specification/Expressions/Anonymous Chức năng (6.23):

Nếu loại dự kiến ​​của hàm nặc danh có dạng scala.Chức năng n [ S , & hellip ;, S n, R], loại dự kiến ​​của eR ...

Vì vậy, loại kết quả của chức năng sẽ được suy ra là List[Int] trừ khi bạn tách định nghĩa chức năng khỏi gán giá trị chức năng (để loại bỏ loại mong đợi):

val function = (x: Int) => (x + 1) 
val plusOne: (List[Int]) => List[Int] = function 

hoặc chỉ định loại chức năng một cách rõ ràng:

val plusOne: (List[Int]) => List[Int] = ((x: Int) => (x + 1)): Int => Int 
1

(Scala 2.9.1-1 (Java HotSpot (TM) 64-Bit Server VM, Java 1.7.0_05)

Một quan sát đầu tiên: Nếu bạn lặp lại fun2ListFun và đổi tên nó thành, ví dụ, `` fun2ListFun, bạn sẽ nhận được

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) 

có vẻ như nếu trình biên dịch xem xét cả implicits như hiện hành.


Một quan sát thứ hai:

Chia

val v: List[String] => List[Int] = ((x: String) => x.length) /* Error*/ 

vào

val f = ((x: String) => x.length) 
val v: List[String] => List[Int] = f /* Works */ 

làm cho trình biên dịch hạnh phúc.

1

Chuyển đổi ngầm định để biên dịch giá trị đầu vào. Vì vậy, chúng tôi chỉ có một vấn đề đối với đầu ra của hàm nặc danh

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) 
} 

Một sửa chữa có thể sử dụng một chuyển đổi ngầm thứ hai:

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) 
} 

Phiên bản này biên dịch.

0

Dường như trình biên dịch có khó khăn trong việc tìm ra những gì đang xảy ra với loại chức năng. Nếu bạn sẽ cho anh ta một chút giúp đỡ, nó sẽ làm việc:

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>