2016-11-06 18 views
6

Câu hỏi này đúng về cú pháp Scala, mặc dù nó chứa một số mã từ akka (như một ví dụ).Tìm hiểu hàm trong scala

Tôi khá mới đối với Scala. Đào vào mã nguồn của AKKA tôi đã đưa ra những điều sau đây phương pháp khá lạ:

def transform[C] 
(f: ExecutionContext ⇒ Materializer ⇒ Future[B] ⇒ Future[C]): Unmarshaller[A, C] = 
Unmarshaller.withMaterializer { implicit ec ⇒ implicit mat ⇒ a ⇒ f(ec)(mat)(this(a)) } 

nơi Unmarshaller.withMaterializer định nghĩa là

def withMaterializer[A, B](f: ExecutionContext ⇒ Materializer => A ⇒ Future[B]): Unmarshaller[A, B] 

gì đang xảy ra ở đây? Chức năng đáng sợ f: ExecutionContext => Materializer => Future[B] => Future[C] là gì. Và điều có vẻ lạ lùng hơn với tôi là dãy số implicit s: implicit ec => implicit mat => a => f(ec)(mat)(this(a)) mặc dù withMaterializer hoàn toàn không có tham số ngầm.

Điều gì ngụ ý có ý nghĩa trong các chuỗi như vậy?

Trả lời

2

f: ExecutionContext => Materializer => Future[B] => Future[C] là gì khác hơn là một hàm cà ri, vì vậy bạn gọi nó như f(ec)(mat)(this(a)) với nhiều tham số danh sách (các danh sách tham số kỹ thuật không thuộc cùng một hàm không giống như def f(...)(...), nhưng đó là các chi tiết). Nói cách khác f có thể được viết như sau:

f: ExecutionContext => { Materializer => { Future[B] => Future[C] } }` 

(chức năng mà trả về một chức năng, trong đó trả thêm một chức năng)

Bây giờ nếu bạn nhìn vào f(ec)(mat)(this(a)) có một cuộc gọi this(a), được định nghĩa ngay trên transform:

def apply(value: A)(implicit ec: ExecutionContext, materializer: Materializer): Future[B] 

(this(a) chỉ đơn giản là một lời kêu gọi this.apply(a)). Bây giờ apply có hai thông số tiềm ẩn, cụ thể là ec: ExecutionContextmaterializer:Materializer, vì vậy, hãy gọi nó là this(a) bạn cần hai giá trị ẩn. Đó chính là định nghĩa của implicit ec ⇒ implicit mat ⇒ a ⇒ f(ec)(mat)(this(a)).Nó tuyên bố ecmat là hàm ý cho tất cả các thân hàm lồng nhau để this(a) có thể chọn chúng. Một khả năng khác là viết:

ec ⇒ mat ⇒ a ⇒ f(ec)(mat)(this(a)(ec, mat)) 
0

Đó là một lambda với các tham số currying và ngầm (được cho là nằm trong phạm vi của khai báo).

Các "đáng sợ" chức năng loại cú pháp là currying: một chức năng của một đối số mà mất ExecutionContext và trả về một chức năng của một lập luận cho rằng phải mất Materializer và trả về chức năng khác, ... vv Một điều nữa là implicit arguments.

Dưới đây là một ví dụ đơn giản của một công trình tương tự:

implicit val implicitInt: Int = 5 
implicit val implicitString: String = "0" 

val f: Int => String => String = { 
    implicit a => { 
    implicit b => { 
     a.toString + b 
    } 
    } 
} 

Đây f là một hàm cà ri mà sẽ đưa Int và trả về một chức năng mà mất String và trả String. Cú pháp chung cho khai báo giá trị hàm là val f = { argument => ... }, vì vậy nếu bạn làm cho đối số này ngầm định, điều đó có nghĩa là phải có một thể hiện kiểu này trong phạm vi sẽ hoạt động như giá trị mặc định. Bạn vẫn có thể áp dụng f cho một số đối số: f(1)(""), bởi vì nó vẫn là một hàm.

Bạn có thể viết lại đoạn code bạn đang hỏi về nhiều một cách chi tiết hơn bằng cách quy định chức năng lồng nhau cho mỗi bước:

def transform[C](f: ExecutionContext ⇒ Materializer ⇒ Future[B] ⇒ Future[C]): Unmarshaller[A, C] = { 

    def getExecutionContext(implicit ec: ExecutionContext): Materializer => (A => Future[B]) = { 

    def getMaterializer(implicit mat: Materializer): A => Future[B] = { 

     def applyF(a: A): Future[B] = f(ec)(mat)(this(a)) 
     applyF // : A => Future[B] 
    } 

    getMaterializer // : Materializer => (A => Future[B]) 
    } 

    Unmarshaller.withMaterializer(
    getExecutionContext // : ExecutionContext => (Materializer => (A => Future[B])) 
) 
} 
+0

Tôi không nghĩ bạn có thể gọi 'f' không có tham số để sử dụng giá trị ẩn. Nó chỉ hoạt động cho các phương thức. 'implicit' trong hàm chức năng nghĩa là đối số là ẩn bên trong phần thân hàm. –

+0

Bạn nói đúng. 'f' không thể sử dụng như một phương thức với các tham số mặc định. Tôi chỉ cố gắng minh họa cho việc xây dựng đó bằng một ví dụ đơn giản hơn, nhưng lấy nó ra khỏi ngữ cảnh. – laughedelic