Functional Programming in Swift [Part 1]
Có rất nhiều ý kiến xung quanh việc swift có phải là Functional Programming hay không và liệu swift có thể viết theo hướng function hay không. Câu trả lời là có. Swift không hẳn là thuần hướng đối tượng, bản thân nó có thể viết theo hướng functional. Trong bài này mình sẽ làm rõ về những tính chất ...
Có rất nhiều ý kiến xung quanh việc swift có phải là Functional Programming hay không và liệu swift có thể viết theo hướng function hay không. Câu trả lời là có. Swift không hẳn là thuần hướng đối tượng, bản thân nó có thể viết theo hướng functional. Trong bài này mình sẽ làm rõ về những tính chất của Functional Programming được tích hợp sẵn trong swift. 1- Cơ bản về Functional Programming Không có một khái niệm chính xác cho Functional Programming. Tùy nhiên có thể hiểu Functional Programming là phương thức giải quyết vấn đề bằng cách chia nhỏ thành các function. Mỗi function lại có input là 1 function khác và output lại là 1 function. Trong quá trình kết nối các function, chúng hạn chế việc thay đổi các state cũng như không quy định rõ thứ tự của các function. Functional Programming coi chương trình như là 1 bài toán (math problem) chứ không phải là 1 chuỗi các thao tác (series operations). Một số lưu ý, Functional Programming là một Declarative Programming Style. Cụ thể, đó là tồn tại 2 style lập trình đó là Imperative programming và Declarative programming, 2 mô hình này khá rộng nên ở đây mình tạm đưa ra khái niệm ngắn gọn. - Imperative programming: telling the “machine” how to do something, and as a result what you want to happen will happen. - Declarative programming: telling the “machine” what you would like to happen, and let the computer figure outhow to do it. Bản chất 2 style này khác nhau về hướng tư duy khi lập trình mà thôi. Như là câu hỏi How - Imperative programming và câu hỏi What - Declarative programming. Functional Programming bản chất là giảm thiểu và kiểm soát các side effects. Bằng cách sử dụng pure function và value type. Đến đây hẳn là đã khá quen thuộc với ai đã biết về swift. Trong swift cũng có đã định nghĩa rất rõ về value type. Cụ thể là Let, struct, dictionary... Điều này thể hiện tính Immutability của Functional Language. Giải thích ngắn gọn là chúng ta không thể set lại giá trị cho một biến, một đối tượng ... nếu sử dụng value type. 2 - First Class Functions Functions là first class type in Swift. Điều này có nghĩa là bạn có thể lưu một function như một biến. Phần này giống với closure của swift
struct UserInfo { let id: Int let name: String let address: String } func getInfoUser(userName: String?, passWord: String?, completion: @escaping (UserInfo) -> Void) { // code }
Trong ví dụ trên mình có một function lấy thông tin user từ api. có 3 tham số, trong đó có một tham số là một function có đối truyền vào là thông tin user và kiểu trả về là void. Sử dụng từ khóa escaping để chỉ ra rằng function này sẽ được gọi tới khi function getInfoUser thực hiện xong. 3 - Pure Functions Pure functions là những hàm rất đơn giản. Chúng có đặc điểm chỉ thực hiện thao tác trên những tham số được truyền vào. Function không thay đổi bất kì biến nào. Nó chỉ đơn giản là nhận vào input và đưa ra output. Không thay đổi state, không tạo ra side-effects.
var name: String? func convertFullName(firstName: String, lastName: String) -> String { return firstName.appending(lastName) }
Function convertFullName nhận vào 2 đối số String và trả về một chuỗi String khác. Nó không tác động vào biến name, không cập nhật giá trị vào biến name. Nó chỉ đọc giá trị là những đầu vào của nó và trả ra một String mới là phép cộng của 2 String truyền vào. Một số tính chất của Pure Functions:
Một pure Function hữu ích phải có nhận tối thiểu một đối số.
func returnNameUser() -> String { return "userName" }
function returnNameUser không nhận vào bất kỳ đối số nào mà chỉ return về một String duy nhất. Rõ ràng returnNameUser là một pure function. Nhưng lúc này nó không khác gì một biến constant. Vậy thay vi khai báo cả một function trong swift chúng ta chỉ cần.
let nameUser: String = "NameUser"
Vậy nên function returnNameUser khi không nhận về gì cả thì nó cũng không có nhiều ý nghĩa. Điều này cũng tương tự với tính chất thứ 2 của pure function.
Một pure function hữu ích phải trả về một giá trị nào đó.
Quay lại với function convertFullName ở trên.
print(convertFullName(firstName: "henry", lastName: "-123"))
Nếu đoạn code trên chạy 3 lần thì sao. Bạn có thể dễ dàng nhận ra nó vẫn sẽ chỉ ra một kết quả. Và dù chạy đến bao nhiều lần đi nữa thì nó cũng chỉ cho ra một kết quả thôi.
Một pure function luôn chỉ có một output với cùng một input
writeFile(fileName) updateDatabaseTable(sqlCommand) sendRequest(apiRequest) openSocket(ipAddress)
Các hàm trên đều có Side Effects. Khi gọi những hàm này, chúng thay đổi files, table trong database, gửi request tới server, hay gọi đến hệ điều hành để lấy socket. Chúng không chỉ tác động tới các tham số truyền vào vậy nên không thể dự đoán được giá trị mà những hàm này sẽ trả về kể cả với một input cho trước. Vậy nên Một pure function không có side effects Với hàng loạt tính chất. Có lẽ bạn sẽ thậy quá khó để làm việc với một pure function. Nhưng hãy nhớ pure function không phải là tất cả của Functional Programming. Functional Programming không thể loại trừ hết các side effects mà chỉ có thể cô lập chúng. Vì chương trình phải tương tác với thế giới bên ngoài, nên một phần nào đó của chương trình phải là không thuần khiết (impure). Mục tiêu của Functional Programming là giảm thiểu tối đa lượng mã nguồn không thuần khiết và tách biệt chúng ra khỏi phần còn lại của chương trình.