Nguyên tắc cơ bản là trong các chức năng lập trình FP thực hiện công việc giống như các đối tượng thực hiện trong lập trình OO. Bạn có thể gọi các phương thức của họ (tốt, dù sao cũng là phương thức "gọi") và họ trả lời theo một số quy tắc nội bộ được đóng gói. Đặc biệt, mọi ngôn ngữ FP phong nha ngoài kia cho phép bạn có "các biến thể hiện" trong hàm của mình với các bao đóng / phạm vi từ vựng.
var make_OO_style_counter = function(){
return {
counter: 0
increment: function(){
this.counter += 1
return this.counter;
}
}
};
var make_FP_style_counter = function(){
var counter = 0;
return fucntion(){
counter += 1
return counter;
}
};
Bây giờ câu hỏi tiếp theo là bạn có ý nghĩa gì với một giao diện? Một cách tiếp cận là sử dụng các giao diện danh nghĩa (nó phù hợp với giao diện nếu nó nói như vậy) - cách tiếp cận này thường phụ thuộc rất nhiều vào ngôn ngữ bạn đang sử dụng vì vậy hãy để nó cho ngôn ngữ sau. Cách khác để xác định một giao diện là cách cấu trúc, xem những gì tham số nhận và trả lại. Đây là loại giao diện mà bạn có xu hướng nhìn thấy trong các ngôn ngữ động, gõ vịt và nó rất phù hợp với tất cả các FP: giao diện chỉ là các loại tham số đầu vào cho các chức năng của chúng tôi và các loại chúng trả về để tất cả các chức năng khớp với đúng loại phù hợp với giao diện!
Do đó, cách đơn giản nhất để biểu diễn một đối tượng khớp với giao diện là chỉ cần có một nhóm các chức năng. Bạn thường nhận được sự xấu xí của việc chuyển các chức năng một cách riêng biệt bằng cách đóng gói chúng trong một số loại hồ sơ:
var my_blarfable = {
get_name: function(){ ... },
set_name: function(){ ... },
get_id: function(){ ... }
}
do_something(my_blarfable)
Sử dụng các chức năng trần trụi hoặc hồ sơ của các chức năng sẽ đi một chặng đường dài trong việc giải quyết hầu hết các vấn đề phổ biến của bạn theo cách "không có chất béo" mà không có hàng tấn nồi hơi. Nếu bạn cần một cái gì đó cao cấp hơn thế, đôi khi các ngôn ngữ cung cấp cho bạn các tính năng bổ sung. Một ví dụ mọi người đề cập là các lớp loại Haskell. Các lớp loại về cơ bản liên kết một loại với một trong các bản ghi các hàm đó và cho phép bạn viết các thứ để từ điển ẩn và được tự động chuyển sang các hàm bên trong nếu thích hợp.
-- Explicit dictionary version
-- no setters because haskell doesn't like mutable state.
data BlargDict = BlargDict {
blarg_name :: String,
blarg_id :: Integer
}
do_something :: BlargDict -> IO()
do_something blarg_dict = do
print (blarg_name blarg_dict)
print (blarg_id blarg_dict)
-- Typeclass version
class Blargable a where
blag_name :: a -> String
blag_id :: a -> String
do_something :: Blargable a => a -> IO
do_something blarg = do
print (blarg_name blarg)
print (blarg_id blarg)
Tuy nhiên, một điều quan trọng cần lưu ý về kiểu chữ là các từ điển được liên kết với các loại chứ không phải với các giá trị (như những gì xảy ra trong từ điển và các phiên bản OO). Điều này có nghĩa là hệ thống loại không cho phép bạn trộn "loại" [1]. Nếu bạn muốn có một danh sách "blargables" hoặc hàm nhị phân tham gia vào blargables thì typeclass sẽ buộc mọi thứ phải cùng loại trong khi cách tiếp cận từ điển sẽ cho phép bạn có các nguồn gốc khác nhau (phiên bản nào tốt hơn phụ thuộc rất nhiều vào bạn đang làm)
[1] Có nhiều cách nâng cao để thực hiện "các loại tồn tại" nhưng thường không đáng để gặp rắc rối.