2011-09-21 15 views
42

Tôi đang làm theo hướng dẫn Pattern matching & functional composition trên các phương thức Scala composeandThen. Có một ví dụ như vậy:Soạn và vàSau đó phương pháp

scala> def addUmm(x: String) = x + " umm" 
scala> def addAhem(x: String) = x + " ahem" 

val ummThenAhem = addAhem(_).compose(addUmm(_)) 

Khi tôi cố gắng sử dụng nó, tôi nhận được một lỗi:

<console>:7: error: missing parameter type for expanded function ((x$1) => addAhem(x$1).compose(((x$2) => addUmm(x$2)))) 
    val ummThenAhem = addAhem(_).compose(addUmm(_)) 
          ^
<console>:7: error: missing parameter type for expanded function ((x$2) => addUmm(x$2)) 
    val ummThenAhem = addAhem(_).compose(addUmm(_)) 
              ^
<console>:7: error: type mismatch; 
found : java.lang.String 
required: Int 
    val ummThenAhem = addAhem(_).compose(addUmm(_)) 

Tuy nhiên, hoạt động này:

val ummThenAhem = addAhem _ compose addUmm _ 

hoặc thậm chí

val ummThenAhem = addAhem _ compose addUmm 

Có gì sai với mã trong hướng dẫn? Không phải biểu thức thứ hai giống như biểu thức đầu tiên không có dấu ngoặc đơn?

Trả lời

38

addAhem là một phương pháp. Phương pháp compose được xác định trên các hàm. addAhem _ chuyển đổi addAhem từ phương thức sang hàm, do đó, compose có thể được gọi trên đó. compose mong đợi một hàm làm đối số của nó. Bạn đang cho nó một phương thức addUmm bằng cách chuyển đổi addUmm thành một hàm có addUmm _ (Dấu gạch dưới có thể bị bỏ qua vì trình biên dịch có thể tự động chuyển đổi phương thức thành hàm khi biết rằng hàm đó vẫn được mong đợi). Vì vậy, mã của bạn:

addAhem _ compose addUmm 

cũng giống như

(addAhem _).compose(addUmm) 

nhưng không

addAhem(_).compose(addUmm(_)) 

PS Tôi không nhìn vào liên kết mà bạn cung cấp.

+0

Vì tính đầy đủ của, ví dụ andThen trông giống như:.. 'val ahemThenUmm = addAhem (_) andThen (addUmm (_)) ' khi nó sẽ giống như ' val ahemThenUmm1 = (addAhem _) andThen (addUmm) ' –

+0

Tôi không chắc chắn về phần được viết trong dấu ngoặc tròn; trình biên dịch * không * chuyển đổi phương thức thành chức năng tự động, ít nhất là đối với Scala 2.10.2. Cách giải quyết khác là khai báo 'addAhem' và' addUmm' làm các hàm để 'compose' hoặc' vàThen' hoạt động mà không có '_'. –

5

Từ compose tài liệu:

Composes two instances of Function1 in a new Function1, with this function applied last.

vì vậy bạn nên viết

scala> val ummThenAhem = (addAhem _).compose(addUmm _) 
ummThenAhem: String => java.lang.String = <function1> 

để điều trị addAhemaddUmm chức năng như áp dụng một phần (nghĩa là function1)

scala> addAhem _ 
res0: String => java.lang.String = <function1> 
2

Tôi tin rằng hướng dẫn được viết cho phiên bản cũ hơn của Scala (có thể là 2.7.7 hoặc cũ hơn). Đã có một số thay đổi trong trình biên dịch kể từ đó, cụ thể là, phần mở rộng cho hệ thống kiểu, mà bây giờ làm cho loại suy luận để thất bại trên:

addUhum(_).compose(addAhem(_)) 

Việc dỡ bỏ để một chức năng vẫn hoạt động với cú pháp rằng nếu bạn chỉ viết:

addUhum(_) 
45

Vâng, điều này:

addUhum _ 

là một mở rộng eta. Nó chuyển đổi các phương thức thành các hàm.Mặt khác, điều này:

addUhum(_) 

là một chức năng ẩn danh. Trong thực tế, nó là một ứng dụng hàm một phần, trong đó tham số này không được áp dụng, và toàn bộ điều được chuyển đổi thành một hàm. Nó mở rộng đến:

x => addUhum(x) 

Quy tắc chính xác để mở rộng có một chút khó giải thích, nhưng về cơ bản, hàm sẽ "bắt đầu" ở dấu phân cách biểu hiện bên trong. Ngoại lệ là các ứng dụng hàm một phần, trong đó "x" được di chuyển ra ngoài hàm - nếu _ được sử dụng thay cho tham số.

Dù sao, đây là cách nó mở rộng:

val ummThenAhem = x => addAhem(x).compose(y => addUmm(y)) 

Alas, loại inferencer không biết loại của x hoặc y. Nếu bạn muốn, bạn có thể thấy chính xác những gì nó đã thử bằng cách sử dụng tham số -Ytyper-debug.

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