Tôi có thể đã lưu trữ các chỉ mục của Đa giác trong Cảnh hiện tại, chỉ mục của điểm được kéo trong Đa giác và thay thế nó mỗi lần. Nhưng cách tiếp cận này không mở rộng quy mô - khi mức độ thành phần lên đến 5 và hơn nữa, nồi hơi sẽ trở nên không thể chịu đựng được.
Bạn hoàn toàn đúng, cách tiếp cận này không mở rộng nếu bạn không thể đi loanh quanh . Cụ thể, bản tóm tắt để tạo Cảnh hoàn toàn mới với một phần phụ nhỏ đã thay đổi. Tuy nhiên, nhiều ngôn ngữ chức năng cung cấp một cấu trúc để xử lý loại thao tác cấu trúc lồng nhau này: ống kính.
Một ống kính về cơ bản là một getter và setter cho dữ liệu bất biến. Một ống kính tập trung vào một số phần nhỏ của cấu trúc lớn hơn. Với một ống kính, có hai điều bạn có thể làm với nó - bạn có thể xem phần nhỏ của giá trị của cấu trúc lớn hơn hoặc bạn có thể đặt phần nhỏ của giá trị của cấu trúc lớn hơn thành giá trị mới. Ví dụ: giả sử bạn có một ống kính tập trung vào mục thứ ba trong danh sách:
thirdItemLens :: Lens [a] a
Kiểu đó có nghĩa là cấu trúc lớn hơn là một danh sách các thứ và phần nhỏ là một trong những thứ đó. Với ống kính này, bạn có thể xem và đặt mục thứ ba trong danh sách:
> view thirdItemLens [1, 2, 3, 4, 5]
3
> set thirdItemLens 100 [1, 2, 3, 4, 5]
[1, 2, 100, 4, 5]
Các ống kính lý do là hữu ích là bởi vì chúng là các giá trị đại diện cho getters và setters và bạn có thể trừu tượng hóa chúng giống như cách bạn có thể các giá trị khác. Bạn có thể tạo các hàm trả về ống kính, ví dụ như listItemLens
hàm lấy số n
và trả về ống kính xem n
mục thứ trong danh sách. Ngoài ra, ống kính có thể được sáng tác :
> firstLens = listItemLens 0
> thirdLens = listItemLens 2
> firstOfThirdLens = lensCompose firstLens thirdLens
> view firstOfThirdLens [[1, 2], [3, 4], [5, 6], [7, 8]]
5
> set firstOfThirdLens 100 [[1, 2], [3, 4], [5, 6], [7, 8]]
[[1, 2], [3, 4], [100, 6], [7, 8]]
Mỗi ống kính đóng gói hành vi để vượt qua một cấp của cấu trúc dữ liệu. Bằng cách kết hợp chúng, bạn có thể loại bỏ bản tóm tắt để vượt qua nhiều cấp cấu trúc phức tạp. Chẳng hạn, giả sử bạn có một scenePolygonLens i
chế độ xem i
Đa giác thứ trong Cảnh và một polygonPointLens n
điểm xem nth
Điểm trong Đa giác, bạn có thể tạo một nhà xây dựng ống kính để chỉ tập trung vào điểm cụ thể mà bạn quan tâm trong toàn bộ cảnh như vậy:
scenePointLens i n = lensCompose (polygonPointLens n) (scenePolygonLens i)
Bây giờ, giả sử người dùng nhấp vào điểm 3 của đa giác 14 và di chuyển nó đúng 10 pixel. Bạn có thể cập nhật cảnh của mình như vậy:
lens = scenePointLens 14 3
point = view lens currentScene
newPoint = movePoint 10 0 point
newScene = set lens newPoint currentScene
Điều này độc đáo chứa tất cả các mẫu soạn thảo để duyệt và cập nhật Cảnh bên trong lens
, tất cả những gì bạn phải quan tâm là những gì bạn muốn thay đổi điểm thành. Bạn có thể trừu tượng hóa điều này bằng một lensTransform
chức năng chấp nhận ống kính, mục tiêu và chức năng cập nhật chế độ xem của mục tiêu thông qua ống kính:
lensTransform lens transformFunc target =
current = view lens target
new = transformFunc current
set lens new target
Điều này có một chức năng và biến nó thành một "trình cập nhật" trên một cấu trúc dữ liệu phức tạp, áp dụng chức năng này chỉ cho chế độ xem và sử dụng nó để xây dựng một chế độ xem mới. Vì vậy, quay trở lại kịch bản di chuyển điểm thứ 3 của đa giác thứ 14 sang 10 pixel bên phải, có thể được biểu thị theo cách lensTransform
tương tự như vậy:
lens = scenePointLens 14 3
moveRightTen point = movePoint 10 0 point
newScene = lensTransform lens moveRightTen currentScene
Và đó là tất cả những gì bạn cần để cập nhật toàn bộ khung cảnh. Đây là một ý tưởng rất mạnh mẽ và hoạt động rất tốt khi bạn có một số chức năng tốt để xây dựng các ống kính xem các phần dữ liệu bạn quan tâm.
Tuy nhiên đây là tất cả những thứ khá hiện có, ngay cả trong cộng đồng lập trình chức năng. Thật khó để tìm thấy sự hỗ trợ thư viện tốt để làm việc với ống kính, và thậm chí còn khó khăn hơn để giải thích cách chúng hoạt động và những lợi ích cho đồng nghiệp của bạn. Thực hiện phương pháp này với một hạt muối.