✨Lập trình hàm

Lập trình hàm

Trong ngành khoa học máy tính, lập trình hàm (lập trình chức năng) là một mô hình lập trình xem việc tính toán là sự đánh giá các hàm toán học và tránh sử dụng trạng thái và các dữ liệu biến đổi. Lập trình hàm nhấn mạnh việc ứng dụng hàm số, trái với phong cách lập trình mệnh lệnh, nhấn mạnh vào sự thay đổi trạng thái. Lập trình hàm xuất phát từ phép tính lambda, một hệ thống hình thức được phát triển vào những năm 1930 để nghiên cứu định nghĩa hàm số, ứng dụng của hàm số, và đệ quy. Nhiều ngôn ngữ lập trình hàm có thể được xem là những cách phát triển giải tích lambda. JavaScript, một trong các ngôn ngữ được dùng nhiều hiện nay, có khả năng lập trình hàm.

Hàm hạng nhất và hàm bậc cao

Hàm bậc cao là các hàm số hoặc có thể nhận các hàm số khác làm tham số hoặc có thể trả về kết quả là hàm số (phép toán vi phân d/dx để tính vi phân của hàm f là một ví dụ của hàm bậc cao trong giải tích).

Các hàm bậc cao có liên hệ chặt chẽ với hàm hạng nhất, ở chỗ các hàm bậc cao và hàm hạng nhất đều cho phép nhận hàm số làm tham số và trả về các hàm khác. Sự khác biệt giữa hai loại này rất mờ nhạt: "bậc cao" mô tả một khái niệm hàm trong toán học tính toán trong các hàm khác, còn "hàm hạng nhất" là một thuật ngữ của ngành khoa học máy tính mô tả các thực thể của ngôn ngữ lập trình trong đó không có giới hạn về việc sử dụng (vì vậy các hàm hạng nhất có thể xuất hiện ở bất cứ đâu trong chương trình, giống như các thực thể hạng nhất khác nhau con số, trong đó có cả việc làm tham số cho các hàm khác và làm giá trị trả về của hàm khác).

Các hàm bậc cao cho phép áp dụng bán phần hoặc currying, một kỹ thuật trong đó hàm lần lượt sử dụng từng tham số của nó, mỗi lần sử dụng lại trả về một hàm mới và chấp nhận tham số tiếp theo. Việc làm này cho phép người lập trình biểu diễn một cách súc tích hàm số kế thừa, tương tự như toán tử cộng sẽ lần lượt cộng từng số tự nhiên lại với nhau.

Hàm thuần túy

Các hàm (hoặc biểu thức) thuần túy hàm không có bộ nhớ hoặc các hiệu ứng lề nhập/xuất. Điều này có nghĩa là các hàm thuần túy có một số đặc tính hữu ích, mà đa số trong chúng có thể dùng để tối ưu mã nguồn:

  • Nếu kết quả của một biểu thức thuần túy không được sử dụng, ta có thể xóa nó đi mà không ảnh hưởng đến các biểu thức khác.
  • Nếu một hàm thuần túy được gọi cùng với các tham số không tạo ra hiệu ứng lề, kết quả sẽ là hằng số tương ứng với danh sách tham số cụ thể (có khi gọi là trong suốt tham chiếu), tức là hàm thuần túy nếu được gọi lần nữa với cùng bộ tham số, kết quả trả về cũng sẽ y hệt như trước (điều này cho phép tối ưu hóa lưu đệm như memoization).
  • Nếu không có sự phụ thuộc về dữ liệu giữa hai biểu thức thuần túy, thì thứ tự của chúng có thể đảo cho nhau, hoặc chúng có thể thực hiện song song mà không ảnh hưởng đến nhau (hay nói cách khác, đánh giá một biểu thức thuần túy bất kỳ là an toàn về luồng (thread-safe)).
  • Nếu toàn bộ ngôn ngữ không cho phép hiệu ứng lề, thì chiến thuật đánh giá hàm nào cũng dùng được; việc này trao cho trình biên dịch quyền tự do sắp xếp lại hoặc phối hợp việc đánh giá biểu thức trong một chương trình (ví dụ, dùng kỹ thuật loại bỏ cây).

Trong khi đa số trình biên dịch dành cho các ngôn ngữ lập trình mệnh lệnh có thể nhận dạng hàm thuần túy, và thực hiện các phép khử biểu thức con thường gặp trong các lệnh gọi hàm thuẫn túy, chúng không thể lúc nào cũng làm như vậy đối với các thư viện đã dịch sẵn, thường không tiết lộ thông tin này, vì thế làm cản trở sự tối ưu hóa liên quan đến các hàm bên ngoài như vậy. Một số trình biên dịch, như gcc, thêm từ khóa bổ sung để giúp lập trình viên đánh dấu hàm nào là hàm thuần túy, để cho phép tối ưu hóa kiểu như vậy. Fortran 95 cho phép hàm được chỉ định "thuần túy".

Đệ quy

Vòng lặp trong các ngôn ngữ hàm thường được thực hiện thông qua đệ quy. Hàm đệ quy sẽ tự gọi chính nó, cho phép thực hiện đi thực hiện lại một tác vụ. Việc đệ quy có thể đòi hỏi phải sử dụng một chồng (stack), nhưng đệ quy đuôi vẫn có thể được trình biên dịch nhận ra và tối ưu hóa nó thành cùng đoạn mã được dùng để hiện thực vòng lặp trong ngôn ngữ mệnh lệnh. Tiêu chuẩn của ngôn ngữ Scheme là phải nhận diện và tối ưu hóa được đệ quy đuôi. Một trong những cách tối ưu hóa đệ quy đuôi là chuyển chương trình thành kiểu truyền liên tiếp trong quá trình dịch.

Các mẫu đệ quy phổ biến đều có thể được khử đệ quy bằng các hàm bậc cao, catamorphism và anamorphism (hay "fold" và "unfold" - gấp và mở gấp) là những ví dụ rõ nhất. Các hàm bậc cao như vậy đóng vai trò tương tự như các cấu trúc điều khiển có sẵn như vòng lặp trong ngôn ngữ mệnh lệnh.

Đa số các ngôn ngữ lập trình hàm đa mục đích đều cho phép đệ quy không giới hạn và là Turing complete, khiến cho bài toán dừng trở nên không quyết định được, có thể gây ra sự thiếu căn cứ cho việc suy diễn công thức, và nói chung đòi hỏi phải có khái niệm không nhất quán trong logic do hệ thống kiểu của ngôn ngữ quy định. Một vài ngôn ngữ lập trình với mục đích đặc biệt như Coq chỉ cho phép đệ quy well-founded và chuẩn hóa mạnh (tính toán không dừng chỉ có thể biểu diễn bằng dòng giá trị vô hạn gọi là codata). Kết quả là, những ngôn ngữ như vậy không phải Turing complete và một số hàm không thể biểu diễn trong ngôn ngữ, dù ngôn ngữ đó vẫn có thể biểu diễn được rất nhiều cách tính toán thú vị mà tránh được vấn đề do đệ quy không giới hạn gây ra. Lập trình hàm giới hạn trong việc đệ quy well-founded với một số ràng buộc khác được gọi là lập trình hàm hoàn toàn (total). Xem Turner 2004 để biết thêm.

Tính toán chặt và không chặt

Có thể chia các ngôn ngữ hàm làm hai loại tùy vào việc chúng sử dụng cách tính toán biểu thức chặt (tham lam) hay không chặt (lười biếng), là những khái niệm chỉ cách xử lý thông số của hàm khi tính toán một biểu thức. Sự khác biệt về các cách tính toán này xuất hiện ở ngữ nghĩa biểu thị của biểu thức khi chúng có chứa phép toán lỗi hoặc có vấn đề. Khi tính toán chặt, việc tính toán số hạng có chứa lỗi cũng sẽ dẫn đến lỗi. Ví dụ, biểu thức: :print length([2+1, 3*2, 1/0, 5-4]) sẽ không tính được theo tính toán chặt vì phép chia không tại phần tử thứ ba của danh sách. Còn với tính toán không chặt, hàm length sẽ trả về giá trị 4, vì khi tính toán hàm, nó không cố gắng tính toán các phần tử trong danh sách. Nói một cách ngắn gọn, tính toán chặt luôn luôn tính toán tất cả cấc số hạng của hàm trước khi xử lý hàm. Tính toán không chặt không tính toán tham số của hàm trừ khi nó cần giá trị đó để tính toán hàm.

Cách hiện thực thông thường của tính toán không chặt trong ngôn ngữ hàm là thu giảm đồ thị. Cách tính toán không chặt được dùng mặc định trong vài ngôn ngữ lập trình hàm thuần túy, như Miranda, Clean và Haskell.

Hughes vào năm 1984 đã phản bác việc dùng tính toán không chặt làm cơ chế để tăng tính module hóa của chương trình thông qua quá trình chia nhỏ bài toán, bằng cách làm cho việc hiện thực độc lập giữa nhà sản xuất và khách hàng dễ dàng hơn. Launchbury 1993 mô tả một số khó khăn mà đánh giá lười biếng tạo ra, cụ thể trong việc phân tích yêu cầu lưu trữ của chương trình, và đề xuất ngữ nghĩa hoạt động để hỗ trợ cho việc phân tích này. Harper 2009 đề xuất đưa cả tính toán chặt lẫn không chặt vào một ngôn ngữ, bằng cách dùng hệ thống kiểu của ngôn ngữ để phân biệt chúng.

Hệ thống kiểu, tính đa hình, kiểu dữ liệu đại số và so trùng mẫu

Đặc biệt kể từ sự phát triển của luận kiểu Hindley–Milner trong thập niên 1970, các ngôn ngữ lập trình hàm có khuynh hướng sử dụng phép tính lambda định kiểu, chống lại phép tính lambda bất định kiểu đã được dùng trong Lisp và các biến thể của nó (như Scheme). Việc sử dụng các kiểu dữ liệu đại số và so trùng mẫu làm cho việc thao tác các cấu trúc dữ liệu phức tạp trở nên thuận tiện và rõ ràng hơn; sự tồn tại của việc kiểm tra kiểu mạnh mẽ trong thời gian biên dịch làm cho các chương trình trở nên đáng tin cậy hơn, trong khi đó luận kiểu giải phóng lập trình viên khỏi việc cần phải khai báo thủ công các kiểu để biên dịch.

Một số ngôn ngữ lập trình hàm định hướng nghiên cứu như Coq, Agda, Cayenne, và Epigram dựa trên lý thuyết kiểu intuitionistic, thuyết này cho phép các kiểu phụ thuộc vào các term. Các kiểu như vậy được gọi là các kiểu phụ thuộc. Các hệ thống kiểu này không có các luận kiểu khả định và rất khó để hiểu và lập trình với chúng. Nhưng các kiểu phụ thuộc này có thể mô tả các mệnh đề tự do trong logic mệnh đề. Thông qua Curry–Howard isomorphism, sau đó, các chương trình định kiểu tốt trong những ngôn ngữ này sẽ trở thành các phương tiện cho việc viết các chứng minh toán học hình thức mà từ đó một trình biên dịch có thể sinh ra mã được chứng nhận. Trong khi những ngôn ngữ này chủ yếu được quan tâm trong nghiên cứu học thuật (kể cả trong toán học hình thức hóa), chúng cũng bắt đầu được sử dụng trong kĩ thuật. Compcert là một trình biên dịch cho một tập con của ngôn ngữ lập trình C được viết bằng Coq và đã được chứng thực chính thức.

Một dạng giới hạn của các kiểu phụ thuộc được gọi là kiểu dữ liệu đại số được khái quát hóa (GADT). Dạng này có thể được thực hiện theo cách cung cấp một vài trong số các lợi ích của lập trình phụ thuộc kiểu trong khi tránh hầu hết sự bất tiện của nó. GADT có sẵn trong Trình biên dịch Glasgow Haskell và trong Scala (như "case classes"), và được cho là phần bổ sung vào các ngôn ngữ khác bao gồm cả Java và C#.

Lập trình hàm trong các ngôn ngữ phi hàm

Có thể sử dụng phong cách hàm của việc lập trình trong các ngôn ngữ mà theo truyền thống không được xem là ngôn ngữ hàm. Một số ngôn ngữ phi hàm đã mượn nhiều đặc điểm như các hàm bậc cao hơn, và các quan niệm danh sách từ các ngôn ngữ lập trình hàm. Điều này làm cho việc chấp nhận phong cách hàm dễ dàng hơn khi sử dụng những ngôn ngữ này. Các cấu trúc hàm như các "hàm bậc cao hơn" và các "danh sách lười" có thể lấy được trong C++ qua các thư viện. Trong C, các con trỏ hàm có thể được dùng để đạt được một vài trong số các hiệu quả của các hàm bậc cao hơn. Ví dụ hàm chung map có thể được thực thi bằng cách dùng các con trỏ hàm. Trong Visual Basic 9 và C# 3.0 và cao hơn, các hàm lambda có thể được dùng để viết các chương trình theo phong cách hàm.

Trong Java, các lớp nặc danh đôi khi được sử dụng để mô phỏng các sự đóng, tuy nhiên các lớp nặc danh không phải luôn luôn là các thay thế chính xác cho các sự đóng bởi vì chúng có nhiều khả năng bị hạn chế hơn.

Nhiều mẫu thiết kế hướng đối tượng có thể biểu đạt bằng các thuật ngữ lập trình hàm: ví dụ, mẫu chiến lược đơn giản chỉ ra cách dùng của hàm bậc cao hơn, và mẫu khách viếng thăm gần như tương ứng với một catamorphism, hoặc fold.

Các ích lợi của dữ liệu bất biến có thể được thấy ngay cả trong các chương trình mệnh lệnh, vì thế các lập trình viên thường xuyên cố gắng làm cho một số dữ liệu bất biến ngay cả trong các chương trình mệnh lệnh.

👁️ 3 | 🔗 | 💖 | ✨ | 🌍 | ⌚
Trong ngành khoa học máy tính, **lập trình hàm** (**lập trình chức năng**) là một mô hình lập trình xem việc tính toán là sự đánh giá các hàm toán học và tránh sử dụng
**D** là một ngôn ngữ lập trình hệ thống hướng đối tượng, dùng câu lệnh, đa mẫu hình do Walter Bright của Digital Mars tạo ra và phát hành năm 2001. Quá trình thiết kế
**Python** () là ngôn ngữ lập trình bậc cao đa năng. Triết lý thiết kế của nó nhấn mạnh khả năng đọc mã bằng cách sử dụng thụt lề đáng kể. Python có kiểu động
thumb|**[[Phép tính lambda** là một hệ thống hình thức để định nghĩa hàm, ứng dụng hàm và đệ quy được Alonzo Church đề xuất vào những năm 193x.]] **Lý thuyết ngôn ngữ lập trình** (thường
**Ruby** là một ngôn ngữ lập trình hướng đối tượng, có khả năng phản ứng. Theo tác giả, Ruby chịu ảnh hưởng bởi Perl, Smalltalk, Eiffel, Ada và Lisp. Ruby cung cấp nhiều mẫu hình
**Kotlin** là một ngôn ngữ lập trình kiểu tĩnh chạy trên máy ảo Java (JVM) và có thể được biên dịch sang mã nguồn Java hay sử dụng cơ sở hạ tầng trình biên dịch
**Lập trình logic hàm** (tiếng Anh: **functional logic programming**) là sự kết hợp mẫu hình lập trình chức năng và lập trình logic thành một ngôn ngữ lập trình duy nhất. Phong cách lập trình
**Haskell** là một ngôn ngữ lập trình thuần hàm, đặt theo tên của Haskell Curry. Vì là ngôn ngữ lập trình hàm, trong Haskell, hàm là "cư dân hạng nhất", với hầu hết các cấu
**Lập trình lượng tử** là quá trình thiết kế hoặc ghép nối các chuỗi lệnh, được gọi là mạch lượng tử, sử dụng các cổng, công tắc và toán tử để điều khiển hệ thống
Trong lập trình hướng đối tượng, **giao thức** (tiếng Anh: _protocol_) hay **giao diện** (_interface_) là một phương tiện phổ biến để các đối tượng không liên quan giao tiếp với nhau. Đây là định
Trong khoa học máy tính, **lập trình ràng buộc** (tiếng Anh: _constraint programming_) là một mẫu hình lập trình trong đó mối quan hệ giữa các biến được mô tả ở dạng các ràng buộc.
**APL** (được đặt tên theo cuốn sách _A Programming Language_) là một ngôn ngữ lập trình được phát triển vào những năm 1960 bởi Kenneth E. Iverson. Kiểu dữ liệu trung tâm của nó là
**R** là một ngôn ngữ lập trình và môi trường phần mềm dành cho tính toán và đồ họa thống kê. Đây là một bản hiện thực ngôn ngữ lập trình S với ngữ nghĩa
**Scala** ( ) là một ngôn ngữ lập trình đa mẫu hình, được thiết kế để tích hợp các tính năng của lập trình hướng đối tượng với lập trình hàm Nó cũng có thể
**Elixir** (phát âm là _Ê-líx-xơ_) là một ngôn ngữ lập trình hàm, đồng thời và đa năng, được chạy trên máy ảo BEAM, thứ còn được sử dụng để thực hiện ngôn ngữ lập trình
Trong khoa học máy tính, **lập trình khai báo** (tiếng Anh: _declarative programming_) là một mẫu hình lập trình theo phong cách xây dựng cấu trúc và các yếu tố của chương trình máy tính
phải|nhỏ|402x402px|[[Mã nguồn của một chương trình máy tính đơn giản được viết bằng ngôn ngữ lập trình C. Khi được biên dịch và chạy, nó sẽ cho kết quả "Hello, world!".]] **Ngôn ngữ lập trình**
**C** là một ngôn ngữ mệnh lệnh được phát triển từ đầu thập niên 1970 bởi Dennis Ritchie để dùng trong hệ điều hành UNIX. Từ đó, ngôn ngữ này đã lan rộng ra nhiều
**Pascal** là một ngôn ngữ lập trình cho máy tính thuộc dạng mệnh lệnh và thủ tục, được Niklaus Wirth phát triển vào năm 1970. Pascal là ngôn ngữ lập trình đặc biệt thích hợp
**C#** (**C Sharp**, đọc là _"xi-sáp"_) là một ngôn ngữ lập trình hướng đối tượng đa năng, mạnh mẽ được phát triển bởi Microsoft, C# là phần khởi đầu cho kế hoạch .NET của họ.
**Lập trình hướng đối tượng** () là một mẫu hình lập trình dựa trên khái niệm "đối tượng", mà trong đó, đối tượng chứa đựng các dữ liệu trong các trường, thường được gọi là
Trong lập trình hướng đối tượng dựa trên lớp, **hàm tạo** (tiếng Anh: _constructor_, viết tắt: _ctor_) trong một lớp là một kiểu chương trình con đặc biệt được dùng để tạo ra đối tượng.
Trong lập trình hướng đối tượng, **lớp** (**class**) là một chương trình-mã-khuôn mẫu có thể mở rộng được để tạo các đối tượng, cung cấp giá trị khởi tạo cho trạng thái (biến thành viên)
Trong khoa học máy tính, **bao đóng** (closure) là một hàm hay một tham chiếu tới một hàm cùng với môi trường tham chiếu - một bảng chứa tham chiếu đến mỗi biến không phải
Phương pháp **lập trình thủ tục** (_procedural programming_) chính là cách thực hiện phương pháp hướng chức năng kể trên. Phương pháp thủ tục chia một chương trình (chức năng) lớn thành các khối chức
Đây là danh sách các thuật ngữ tìm thấy trong lập trình hướng đối tượng. Một số có liên quan đến lập trình hướng đối tượng và một số thì không. Lưu ý rằng, các
nhỏ|Ảnh chụp màn hình tài liệu [[API web viết bởi NASA]] Một **giao diện lập trình ứng dụng** (, viết tắt: _API_) là một giao diện mà một hệ thống máy tính hay ứng dụng
Trong lập trình, **tham số** là biến được thu nhận bởi một chương trình con. Tại thời gian chạy, chương trình con sử dụng các giá trị được gán cho các tham số để thay
nhỏ|Cbmain Trong khoa học máy tính, một **ngôn ngữ lập trình bậc cao** (tiếng Anh: _high-level programming language_) là một ngôn ngữ lập trình có sự trừu tượng hóa mạnh mẽ khỏi các chi tiết
**Go** là một ngôn ngữ lập trình mới do Google thiết kế và phát triển. Nó được kỳ vọng sẽ giúp ngành công nghiệp phần mềm khai thác tối đa nền tảng đa lõi của
Trong lập trình hướng đối tượng, **hàm hủy** (tiếng Anh: _destructor_, viết tắt: _dtor_) là một phương thức được gọi tự động để hủy bỏ một đối tượng. Điều này xảy ra khi thời gian
thumb|Các vòng lặp lên kế hoạch và phản hồi trong lập trình cực hạn **Lập trình cực hạn** (tiếng Anh: **Extreme programming**, viết tắt là **XP**) là một quy trình phát triển phần mềm nhằm
Trong điện toán, **lập trình hướng khía cạnh** (tiếng Anh: _aspect-oriented programming_, viết tắt: _AOP_) là một mẫu hình lập trình nhằm tăng tính mô đun bằng cách cho phép phân tách những mối quan
Programming Paradigm hay **Phương thức lập trình** là một kiểu cơ bản của lập trình vi tính (Computer Programming). Paragigm với các khái niệm và sự trừu tượng dùng trong mô tả các thành phần
**Lập trình cấu trúc** là một tập con của lập trình thủ tục. Trong một chương trình máy tính, các khối chức năng có thể được thực hiện không chỉ theo trình tự mà còn
**Dylan** là một ngôn ngữ lập trình đa mẫu hình có hỗ trợ hàm, lập trình hướng đối tượng (OOP), động và phục hồi trong khi cung cấp một mô hình lập trình được thiết
Trong tin học, **mẫu hình lập trình** là một kiểu lập trình _kiểu có tính mẫu hình_ trong tiến hành về công nghệ phần mềm. Một mẫu hình lập trình cung cấp (xác định) quan
**Ada** là ngôn ngữ lập trình xuất xứ từ Bộ quốc phòng Mỹ vào khoảng nửa đầu thập niên 80 của thế kỷ 20. Ngôn ngữ này được đặt tên theo Ada Augusta nữ bá
**Swift** là một ngôn ngữ lập trình hướng đối tượng dành cho việc phát triển iOS và macOS, watchOS, tvOS và z/OS. được giới thiệu bởi Apple tại hội nghị WWDC 2014. Swift được mong
Đây là danh sách các ngôn ngữ lập trình đáng chú ý, được nhóm theo loại. Vì không có sơ đồ phân loại bao quát cho các ngôn ngữ lập trình, nên trong nhiều trường
Các ngôn ngữ lập trình thường hỗ trợ một tập các **toán tử** (_operator_): nó có hành vi gần giống như hàm, nhưng có cú pháp và ngữ nghĩa khác với hàm thông thường. Các
**Lập trình dựa trên nguyên mẫu** (tiếng Anh: **prototype-based programming**) là một kiểu lập trình hướng đối tượng, trong đó việc tái sử dụng hành vi (được gọi là kế thừa) được thực hiện thông
Trong lập trình máy tính, **lập trình hướng sự kiện**, hay chính xác là **lập trình dẫn động bằng sự kiện** (tiếng Anh: **Event-driven programming**), là một mẫu hình lập trình trong đó luồng của
thumb|Phương thức Factory trong [[LePUS3]] Trong lập trình hướng đối tượng (OOP), **factory** (_nhà máy_) là một đối tượng để tạo đối tượng khác – một cách chính thức thì factory là một hàm hay
Trong lập trình máy tính, một **khối** (tiếng Anh: _block_) hay **khối mã** (_code block_) là một cấu trúc từ vựng của mã nguồn được nhóm lại với nhau. Các khối bao gồm một hay
**Đóng gói** (tiếng Anh: _encapsulation_) trong ngôn ngữ lập trình là thuật ngữ dùng để chỉ một trong hai khái niệm khác nhau nhưng có liên quan với nhau, đôi khi còn chỉ sự kết
**Lập trình hướng đối tượng đồng thời** là một mô hình lập trình kết hợp lập trình hướng đối tượng (OOP) cùng với đồng thời. Trong khi nhiều ngôn ngữ lập trình, như Java, kết
**CLU** là một ngôn ngữ lập trình được tạo ra ở Viện Công nghệ Massachusetts (MIT) bởi Barbara Liskov và các sinh viên của bà trong khoảng thời gian từ 1974 đến 1975. Mặc dù
**Lập trình tổng quát** (tiếng Anh: _generic programming_) là một dạng lập trình máy tính mà trong đó thuật toán được viết theo cách kiểu _được-xác-định-sau_ và sau đó được _khởi tạo_ (_instantiate_) nếu cần
Trong khoa học máy tính, **hàm nội tuyến** (tiếng Anh: _inline function_) là một cấu trúc trong ngôn ngữ lập trình được sử dụng để đề nghị với chương trình biên dịch rằng một hàm