Draft:Ứng dụng một phần

Trong Khoa học máy tính, ứng dụng một phần (hay ứng dụng một phần hàm) đề cập đến quá trình cố định một đối số của một hàm, tạo ra một hàm khác có số lượng nhỏ hơn. Cho một hàm f \colon (X \times Y \times Z) \to N, chúng ta có thể sửa (hoặc 'liên kết') đối số đầu tiên, tạo ra một hàm loại \text{partial}(f) \colon (Y \times Z) \to N. Đánh giá chức năng này có thể được biểu diễn dưới dạng f_{partial}(2, 3). Lưu ý rằng kết quả của việc áp dụng một phần hàm tỏng trường hợp này là một hàm có hai đối số. Ứng dụng một phần đôi khi được gọi không chính xác là currying, đây là một khái niệm có liên quan, nhưng khác biệt.

Động lực
Theo trực giác, ứng dụng hàm từng phần cho biết "nếu bạn sửa các tham số đầu tiên của hàm, bạn sẽ nhận được hàm của các đối số còn lại". Ví dụ, nếu hàm div(x,y) = x/y, sau đó div với tham số x cố định ở 1 là một hàm khác: div1(y) = div(1,y) = 1/y. Điều này giống như hàm inv trả về nghịch đảo nhân của đối số của nó, được xác định bởi inv(y) = 1/y.

Động lực thực tế của việc áp dụng từng phần là rất thường các hàm thu được bằng cách cung cấp một số chứ không phải tất cả các đối số cho một hàm đều hữu ích; ví dụ: nhiều ngôn ngữ có chức năng hoặc toán tử tương tự như. Ứng dụng một phần giúp dễ dàng xác định các hàm này, ví dụ bằng cách tạo một hàm đại diện cho toán tử cộng với giới hạn 1 làm đối số đầu tiên.

Phát triển
Trong các ngôn ngữ như ML, Haskell và F#, theo mặc định, các hàm được xác định ở dạng curried. Việc cung cấp ít hơn tổng số đối số được gọi là áp dụng một phần.

Trong các ngôn ngữ có chức năng hạng nhất, người ta có thể định nghĩa curry, uncurry và papply để thực hiện currying và ứng dụng một phần một cách rõ ràng. Điều này có thể phát sinh chi phí thời gian chạy lớn hơn do tạo ra các bao đóng bổ sung, trong khi Haskell có thể sử dụng các kỹ thuật hiệu quả hơn.

Scala triển khai ứng dụng một phần tùy chọn với trình giữ chỗ, ví dụ: def add(x: Int, y: Int) = {x+y}; add(1, _: Int) trả về một hàm tăng dần. Scala cũng hỗ trợ nhiều danh sách tham số như cà ri, ví dụ: def add(x: Int)(y: Int) = {x+y}; add(1) _.

Clojure triển khai ứng dụng một phần bằng cách sử dụng  hàm được xác định trong thư viện lõi của nó.

Thư viện chuẩn C++ cung cấp bind(function, args..) để trả về một đối tượng hàm là kết quả của việc áp dụng một phần các đối số đã cho vào hàm đã cho. Vì C++20 nên hàm  cũng được cung cấp để liên kết các đối số   đầu tiên của hàm với args. Ngược lại, liên kết cho phép liên kết bất kỳ đối số nào của hàm được truyền cho nó, không chỉ các đối số đầu tiên. Ngoài ra, biểu thức lambda có thể được sử dụng: Trong Java,  áp dụng một phần hàm cho đối số đầu tiên của nó. Ngoài ra, kể từ Java 8, lambdas có thể được sử dụng: Trong Raku, phương thức giả định tạo ra một hàm mới với ít tham số hơn.

Mô-đun thư viện chuẩn Python  bao gồm hàm một phần, cho phép liên kết đối số theo vị trí và được đặt tên, trả về một hàm mới.

Trong XQuery, một phần giữ chỗ tham số (?) được sử dụng cho mỗi đối số không cố định trong ứng dụng hàm một phần.

Các định nghĩa
Trong phép tính lambda được gõ đơn giản với ứng dụng một phần hàm và loại sản phẩm (λ→,×), việc nấu cà ri và không nấu chín có thể được định nghĩa là


 * (((a &#xD7; b) → c) &#xD7; a) → (b → c) = λ(f, x). λy. f (x, y)
 * (((a &#xD7; b) → c) &#xD7; a) → (b → c) = λ(f, x). λy. f (x, y)


 * ((a &#xD7; b) → c) → (a → (b → c)) = λf. λx. λy. f (x, y)
 * ((a &#xD7; b) → c) → (a → (b → c)) = λf. λx. λy. f (x, y)


 * (a → (b → c)) → ((a &#xD7; b) → c) = λf. λ(x, y). f x y
 * (a → (b → c)) → ((a &#xD7; b) → c) = λf. λ(x, y). f x y

Lưu ý    =.

Công thức toán học và ví dụ
Ứng dụng từng phần có thể là một cách hữu ích để xác định một số khái niệm hữu ích trong toán học.

Tập hợp đã cho $$X, Y$$ và $$Z$$, và một hàm $$f: X\times Y \rightarrow Z$$, người ta có thể định nghĩa hàm như sau:


 * $$ f(\,\cdot\,, -): X\rightarrow (Y\rightarrow Z),$$

trong đó $$(Y\rightarrow Z)$$ là tập hợp các hàm $$Y\rightarrow Z$$. Hình ảnh của $$x\in X$$ dưới bản đồ này là $$f(x, \,\cdot\,):Y\rightarrow Z$$. Đây là chức năng gửi $$ y \in Y$$ đến $$f(x,y)$$. Thường có các cấu trúc trên $$X, Y, Z$$ có nghĩa là hình ảnh của $$f(\,\cdot\, ,-)$$ giới hạn ở một số tập hợp con của hàm $$Y\rightarrow Z$$, như được minh họa trong các ví dụ sau.

Tác động nhóm
Một tác động nhóm có thể hiểu là một chức năng$$* : G\times X \rightarrow X$$. Việc đánh giá một phần \rho: G \rightarrow \text{Sym}(X)\subset (X\rightarrow X) giới hạn nhóm các song ánh từ chính nó. Tiên đề hành động nhóm còn đảm bảo $$\rho$$thêm tính đồng cấu nhóm.

Sản phẩm bên trong và bản đồ chính tắc cho kép
Một sản phẩm bên trong trên không gian vectơ $$V$$ trên một trường $$K$$ là một bản đồ $$\phi:V\times V\rightarrow K$$. Việc đánh giá từng phần cung cấp một bản đồ chính tắc cho không gian vectơ kép, $$\phi(\, \cdot \, ,-):V\rightarrow V^*\subset (V\rightarrow K)$$. Nếu đây là tích bên trong của không gian Hilbert thì định lý biểu diễn Riesz đảm bảo rằng đây là một phép đẳng cấu.

Tích chéo và bản đồ kề của đại số Lie
Ứng dụng từng phần của tích chéo $$\times$$ trong $$\mathbb{R}^3$$ là $$\times(\, \cdot \,, -): \mathbb{R}^3 \mapsto \text{End}(\mathbb{R}^3)$$. Hình ảnh của vectơ $$\mathbf{u}$$ là một bản đồ tuyến tính $$T_\mathbf{u}$$ như là $$T_\mathbf{u}(\mathbf{v}) = \mathbf{u}\times\mathbf{v}$$. Các thành phần của $$T_\mathbf{u}$$ có thể được coi là$$(T_\mathbf{u})_{ij} = \epsilon_{ijk}u_k$$.

Điều này liên quan chặt chẽ đến bản đồ liền kề của đại số Lie. Đại số Lie được trang bị một dấu ngoặc [\, \cdot \,, \, \cdot \,]:\mathfrak{g}\times\mathfrak{g}\rightarrow \mathfrak{g}. Ứng dụng một phần cung cấp một bản đồ \text{ad}:\mathfrak{g}\rightarrow \text{End}(\mathfrak{g}). Các tiên đề cho dấu ngoặc đảm bảo bản đồ này là sự đồng cấu của đại số Lie.

Kiến thức liên quan

 * η-conversion
 * POP-2
 * Restriction (toán học), hiện tượng tổng quát hơn về việc hạn chế một hàm vào một tập con của miền xác định của nó

Xem thêm

 * Benjamin C. Pierce et al. "Partial Application",
 * "Digression: Currying". Software Foundations.
 * "Digression: Currying". Software Foundations.

Category:Functional programming