Làm thế nào là các thực thể với một bản sắc và một trạng thái liên tục có thể thay đổi được mô hình hóa trong một ngôn ngữ lập trình chức năng?


8

Trong câu trả lời cho câu hỏi này (được viết bởi Pete), có một số cân nhắc về OOP so với FP. Cụ thể, có ý kiến ​​cho rằng các ngôn ngữ FP không phù hợp lắm để mô hình hóa các đối tượng (liên tục) có bản sắc và trạng thái có thể thay đổi.

Tôi đã tự hỏi nếu điều này là đúng hay nói cách khác, làm thế nào người ta sẽ mô hình hóa các đối tượng trong một ngôn ngữ lập trình chức năng. Từ kiến ​​thức cơ bản của tôi về Haskell, tôi nghĩ rằng người ta có thể sử dụng các đơn vị theo một cách nào đó, nhưng tôi thực sự không biết đủ về chủ đề này để đưa ra một câu trả lời rõ ràng.

Vì vậy, làm thế nào các thực thể có bản sắc và trạng thái bền bỉ có thể thay đổi thường được mô hình hóa bằng ngôn ngữ chức năng?

Dưới đây là một số chi tiết để làm rõ những gì tôi có trong tâm trí. Lấy một ứng dụng Java điển hình trong đó tôi có thể (1) đọc bản ghi từ bảng cơ sở dữ liệu vào đối tượng Java, (2) sửa đổi đối tượng theo các cách khác nhau, (3) lưu đối tượng đã sửa đổi vào cơ sở dữ liệu.

Làm thế nào điều này sẽ được thực hiện, ví dụ như trong Haskell? Ban đầu tôi sẽ đọc bản ghi thành một giá trị bản ghi (được xác định bởi định nghĩa dữ liệu), thực hiện các phép biến đổi khác nhau bằng cách áp dụng các hàm cho giá trị ban đầu này (mỗi giá trị trung gian là một bản sao mới, được sửa đổi của bản ghi gốc) và sau đó viết giá trị bản ghi cuối cùng đến cơ sở dữ liệu.

Đây có phải là tất cả không? Làm thế nào tôi có thể đảm bảo rằng tại mỗi thời điểm chỉ có một bản sao của hồ sơ là hợp lệ / có thể truy cập được? Người ta không muốn có các giá trị bất biến khác nhau đại diện cho các ảnh chụp nhanh khác nhau của cùng một đối tượng có thể truy cập cùng một lúc.


Phụ thuộc vào một ngôn ngữ. Rich Hickey, tác giả của Clojure khuyên bạn nên sử dụng các cấu trúc dữ liệu (danh sách, từ điển, bộ, v.v.) để thể hiện dữ liệu của bạn. Tôi không hoàn toàn bán trên ý tưởng; Tôi thích hủy tham chiếu các trường theo tên của chúng hơn là chỉ mục hoặc ghi nhớ và kiểm tra trình biên dịch mà tôi không làm hỏng. F # có cấu trúc, giống như các lớp. msdn.microsoft.com/en-us/l Library / dd233233.aspx Ngay cả khi sử dụng Java hoặc C #, bạn có thể có các đối tượng bất biến có thể "thay đổi" bằng cách tạo một đối tượng hoàn toàn mới.
Công việc

1
@gnat: Cảm ơn bạn đã chỉnh sửa tiêu đề: các đối tượng chắc chắn không phải là thuật ngữ phù hợp nhất.
Giorgio

Câu trả lời:


7

Cách thông thường để nói về những thay đổi trạng thái trong một ngôn ngữ thuần túy như Haskell là mô hình hóa chúng thành các hàm lấy trạng thái cũ và trả về một phiên bản sửa đổi. Ngay cả đối với các đối tượng phức tạp, điều này vẫn hiệu quả do chiến lược đánh giá lười biếng của Haskell - mặc dù bạn đang tạo một đối tượng mới, nhưng nó không được sao chép toàn bộ; mỗi lĩnh vực chỉ được đánh giá khi cần thiết.

Nếu bạn có nhiều hơn một vài thay đổi trạng thái cục bộ, mọi thứ có thể trở nên vụng về, đó là nơi các đơn nguyên xuất hiện. Mô hình đơn nguyên có thể được sử dụng để gói gọn một trạng thái và những thay đổi của nó; ví dụ trong sách giáo khoa là Stateđơn nguyên đi kèm với bản cài đặt Haskell tiêu chuẩn. Tuy nhiên, lưu ý rằng một đơn nguyên không có gì đặc biệt: đó chỉ là một loại dữ liệu phơi bày hai phương thức ( >>=return) và đáp ứng một số kỳ vọng ('luật đơn nguyên'). Dưới vỏ bọc, đơn vị Nhà nước thực hiện chính xác như vậy: lấy trạng thái cũ và trả lại trạng thái đã sửa đổi; chỉ cú pháp là đẹp hơn.


2
Tôi nghĩ rằng sự lười biếng là từ sai, Nó hiệu quả vì Haskell có thể chia sẻ các thành phần con chưa được sửa đổi của nhà nước. Điều này có thể xảy ra trong bất kỳ ngôn ngữ nào đặt tính đột biến ở cấp độ loại.
Daniel Gratzer

@jozefg - mặc dù điều đó có thể đúng, nhưng ở Haskell ít nhất việc thực hiện nó vốn gắn liền với sự lười biếng của ngôn ngữ; nó chỉ đơn giản hoạt động vì toàn bộ giá trị của cấu trúc chỉ được tính khi được yêu cầu và chuỗi thunks đại diện cho các bản cập nhật được đánh giá tại thời điểm đó và chỉ khi cần thiết để xác định giá trị mới nhất của thành viên được yêu cầu là gì. Các ngôn ngữ nghiêm ngặt thuần túy cần các hoạt động cập nhật hồ sơ như một nguyên thủy để có hiệu quả; Haskell không vì sự lười biếng của nó.
Jules

2

Tôi không phải là nhà phát triển ngôn ngữ chức năng, vì vậy xin hãy bắn tôi xuống nếu tôi có lỗi này, nhưng nếu đúng, nó có thể là một sự tương tự thú vị.

Tôi đã từng nói rằng Excel về cơ bản là một ngôn ngữ chức năng. Tôi không nói về VBA và cứ thế, tôi đang nói về những gì xảy ra trên trang tính.

Vì vậy, bạn có các đầu vào, có thể là bảng, các ô riêng lẻ hoặc các phạm vi được đặt tên, v.v. và thông qua một chuỗi các hoạt động mà bạn kết thúc với một kết quả hoặc nhiều kết quả. Thay đổi một đầu vào và nó ngay lập tức chảy qua.

Sự tương tự đó có giữ nước không?


1
Theo lập luận từ chính quyền , bạn đã đúng;)
phant0m

1
Tôi tin rằng việc sử dụng Excel giống như lập trình dataflow , nhưng có một chút chậm trễ trong việc Excel có thể phù hợp. Cá nhân, tôi không chắc chắn tôi sẽ gọi nó là ngôn ngữ ngay từ đầu ...
Izkata

1
Bạn có một điểm. Tuy nhiên, Excel vẫn hoạt động trong vấn đề đó. Tái bút: Tôi khuyên bạn nên xem bài thuyết trình, tôi nghĩ nó khá thú vị.
phant0m

@Izkata Excel sẽ đại diện cho một trường hợp đặc biệt của lập trình dataflow: lập trình phản ứng
itbruce

2

Tôi sẽ nói rằng bạn đang nói về đặc tính phi trạng thái của ngôn ngữ chức năng thuần túy.

Bạn lấy trạng thái ban đầu làm đầu vào, bạn trả về trạng thái cuối cùng làm đầu ra. Không có gì khác biệt cơ bản với những gì bạn làm trong một ngôn ngữ với khái niệm trạng thái, ngoại trừ việc bạn rõ ràng hơn về nó và điều đó có thể tẻ nhạt và kém hiệu quả (*).

Lưu ý rằng bạn không nhất thiết phải sửa đổi tất cả các vị trí tham chiếu đối tượng của mình: chúng có thể giữ mã thông báo và sau đó bạn chỉ cần sửa đổi cấu trúc dữ liệu ánh xạ mã thông báo sang trạng thái hiện tại của chúng. Đến lúc đó, bạn đang thực hiện một hệ thống toàn trạng thái bằng ngôn ngữ không trạng thái và bạn nhận lại các vấn đề của ngôn ngữ toàn trạng thái.


(*) Ví dụ, tôi đã tìm kiếm - và không tìm thấy - cấu trúc dữ liệu cho phép tôi trả về O (1) bản sao được sửa đổi của cấu trúc dữ liệu có thể được lập chỉ mục bởi các số nguyên liên tiếp trong O (1).


+1. Có, tôi đã đề cập đến việc mô hình hóa một thực thể có trạng thái như một đối tượng (có bản sắc và lịch sử của các trạng thái tiếp theo) bằng ngôn ngữ không trạng thái. Điều gì sẽ là đối tác của ví dụ của bạn (được đánh dấu bằng (*)) trong một ngôn ngữ như Java? Một mảng? Một mảng các đối tượng?
Giorgio

@Giorgio, vâng. Tôi biết làm thế nào để làm điều này trong O (log n), nhưng không phải O (1) - và sau đó yếu tố không đổi cũng là một điểm nhấn. Lưu ý rằng tôi đã sử dụng các cấu trúc dữ liệu được thiết kế cho ngôn ngữ chức năng thuần túy như một cách để thực hiện hoàn tác trong các ngôn ngữ toàn trạng thái.
Lập trình viên

Ngẫu nhiên, một trie về mặt kỹ thuật là O (1) theo cùng một giả định đơn giản hóa thường được sử dụng khi thảo luận về những điều đó, là một bộ sưu tập có kích thước thay đổi với các thao tác chèn / xóa mà độ phức tạp thời gian không phụ thuộc vào số lượng phần tử hiện diện. Tuy nhiên, chúng không thực sự có thể so sánh với một mảng có thể thay đổi.
CA McCann

Một danh sách liên kết thông thường [(Int, v)]sẽ cho phép bạn thay thế giá trị tại bất kỳ chỉ mục nào trong thời gian không đổi bằng cách đơn giản sử dụng giá trị mới. Nhược điểm: giá trị cũ vẫn lấy RAM và tìm kiếm là tuyến tính.
singpolyma

1

Nói tóm lại, mỗi trạng thái của một thực thể là thực thể riêng của nó. Vì vậy, trong logic kinh doanh "đặt hàng" cổ điển của bạn, có một Orderthực thể và một OrderVersionthực thể. Cả hai đều bất biến. Logic thêm một mục hàng lấy phiên bản cũ và mới OrderLineItemVersionlàm đầu vào và trả về một OrderVersionthực thể mới .

Nó làm cho một số thứ dễ dàng hơn (đặc biệt là chức năng "hoàn tác"), nhưng một số thứ khó hơn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.