Tôi sẽ quan tâm đến một ví dụ nhỏ của van Laarhoven isomorphism lenses, được áp dụng cho một kiểu dữ liệu như data BValue = BValue { π :: Float, σ :: Float, α :: Float } deriving Show
(cụ thể là các chức năng get/set/modify). Cảm ơn bạn trước.Ống kính đẳng cấu
Trả lời
Từ bài van Laarhoven của, loại Lens
là
data Lens a b = forall r . Lens (Iso a (b, r))
Vì vậy, trong trường hợp của chúng tôi a
là BValue
và chúng tôi muốn xây dựng một số leneses đó chọn ra một hoặc nhiều các yếu tố. Vì vậy, ví dụ, hãy xây dựng một ống kính chọn ra π.
piLens :: Lens BValue Float
Vì vậy, nó sẽ là một ống kính từ một BValue
đến một Float
piLens = Lens (Iso {fw = piFwd, bw = piBwd})
Một ống kính chọn ra hai điều (cụ thể là người đầu tiên trong ba, với nhãn pi.): A còn lại loại r
(bỏ qua ở đây vì chúng tôi không phải chỉ định rõ ràng một loại tồn tại trong haskell), và một đẳng cấu. Một đẳng cấu là lần lượt bao gồm một chuyển tiếp và một chức năng lạc hậu.
piFwd :: BValue -> (Float, (Float, Float))
piFwd (BValue {pi, sigma, alpha}) = (pi, (sigma, alpha))
Chức năng chuyển tiếp chỉ cách ly thành phần chúng tôi muốn. Lưu ý rằng loại dư của tôi ở đây là "phần còn lại của giá trị", cụ thể là một cặp sigma và phao alpha.
piBwd :: (Float, (Float, Float)) -> BValue
piBwd (pi, (sigma, alpha)) = BValue { pi = pi, sigma = sigma, alpha = alpha }
Chức năng lạc hậu là tương tự.
Bây giờ chúng tôi đã xác định ống kính để thao tác thành phần pi của BValue
.
Bảy ống kính khác tương tự nhau. (7 ống kính: chọn ra sigma và alpha, chọn tất cả các cặp có thể (bỏ qua thứ tự), chọn tất cả BValue
và chọn ra ()
).
Một chút tôi không chắc chắn về độ nghiêm ngặt: Tôi hơi lo lắng rằng các hàm fw và bw tôi đã viết quá nghiêm ngặt. Không chắc.
Chúng tôi đang chưa xong:
Chúng tôi vẫn cần phải kiểm tra xem piLens
thực sự tôn trọng pháp luật ống kính. Điều tốt đẹp về định nghĩa của Van Laarhoven là Lens
là chúng ta chỉ phải kiểm tra các định luật đẳng cấu; các luật ống kính tuân theo tính toán trong bài đăng trên blog của anh ấy.
Vì vậy, nghĩa vụ chứng minh của chúng tôi là:
fw piLens . bw piLens = id
bw piLens . fw piLens = id
Cả hai chứng minh làm theo trực tiếp từ các định nghĩa của piFwd
và piBwd
và pháp luật về thành phần.
Khám phá , triển khai thấu kính cho các loại bản ghi.
Để minh họa gói này, hãy lấy hai kiểu dữ liệu ví dụ sau.
import Data.Label import Prelude hiding ((.), id) data Person = Person { _name :: String , _age :: Int , _isMale :: Bool , _place :: Place } data Place = Place { _city , _country , _continent :: String }
Cả hai kiểu dữ liệu đều là loại bản ghi với tất cả các nhãn có dấu gạch dưới. Dấu gạch dưới này là một dấu hiệu cho mã Haskell mẫu của chúng tôi để lấy được các ống kính cho các trường này. Ống kính có thể được thực hiện với lớp lót đơn giản này:
$(mkLabels [''Person, ''Place])
Đối với tất cả các nhãn, ống kính sẽ được tạo.
Bây giờ hãy xem ví dụ này. Người bạn cũ 71 tuổi này, hàng xóm của tôi tên là Jan, không ngại sử dụng anh ta như một ví dụ:
jan :: Person jan = Person "Jan" 71 True (Place "Utrecht" "The Netherlands" "Europe")
Khi chúng ta muốn chắc chắn Jan thực sự già như anh ta tuyên bố chúng ta có thể sử dụng hàm get để lấy độ tuổi dưới dạng số nguyên:
hisAge :: Int hisAge = get age jan
Cân nhắc bây giờ anh ấy muốn chuyển đến Amsterdam: nơi nào tốt hơn để dành ngày cũ của bạn. Sử dụng thành phần chúng ta có thể thay đổi giá trị thành phố sâu bên trong cấu trúc:
moveToAmsterdam :: Person -> Person moveToAmsterdam = set (city . place) "Amsterdam"
Và bây giờ:
ghci> moveToAmsterdam jan Person "Jan" 71 True (Place "Amsterdam" "The Netherlands" "Europe")
Thành phần được thực hiện bằng cách sử dụng toán tử là một phần của các mô-đun Control.Category (.). Đảm bảo nhập mô-đun này và ẩn hàm (.) Id mặc định từ Haskell Prelude.
- 1. Ống kính chức năng
- 2. Kết hợp ống kính
- 3. Construct predicates với ống kính
- 4. Scalaz: cách tạo ống kính bản đồ với ống kính giá trị?
- 5. Ống kính được sử dụng/hữu ích cho là gì?
- 6. cây ngang với Ống kính và Dây khóa kéo
- 7. Bắt nhiều kết quả từ bản đồ với "ống kính"
- 8. Ống kính Windows Phone 8 tăng cường thực tế
- 9. Tạo ống kính cho thư viện "ống kính" với bộ xử lý tên tùy chỉnh thay vì mặc định "gạch dưới" dựa trên một
- 10. Kết cấu bình đẳng trong F #
- 11. Chèn vào danh sách tại một vị trí cụ thể bằng cách sử dụng ống kính
- 12. Ứng dụng thực tế của "Chuối, ống kính, phong bì và dây thép gai"?
- 13. đây có phải là điểm dành cho ống kính chức năng trong javascript không?
- 14. Sự bình đẳng của hai cấu trúc trong C#
- 15. Có thể xây dựng một kỷ lục mới bằng cách sử dụng Ống kính không?
- 16. Tôi làm cách nào để tạo các ống kính từ một bản ghi trong GHCi
- 17. Làm thế nào để tạo hiệu ứng ống kính mắt cá của OpenGL?
- 18. Cập nhật nhiều trường con của trường bằng cách sử dụng Ống kính ekmett
- 19. Tránh lặp lại sử dụng ống kính trong khi sâu sao chép vào Bản đồ giá trị
- 20. tương đẳng cho bình đẳng heterogenous
- 21. Làm thế nào để tạo ra ống kính đa hoặc xem trước sử dụng một máy ảnh trong Android
- 22. FindChessboardCorners không thể phát hiện bàn cờ trên hình ảnh rất lớn bằng ống kính tiêu cự dài
- 23. "Thử nghiệm đẳng cấp bình đẳng" trong mục tiêu-c
- 24. C#: Biểu mẫu kính?
- 25. Kính cắt Delphi
- 26. Python: subprocess.call bị hỏng ống
- 27. Octave/MATLAB: Làm thế nào để so sánh các cấu trúc cho sự bình đẳng?
- 28. Thư viện để kiểm tra xem hai biểu thức chính quy có bằng nhau/đẳng cấu
- 29. Hiệu ứng kính - Hiệu ứng nghệ thuật
- 30. bình đẳng với Double.NaN
Điều cuối cùng: Không có chức năng nhận/đặt/sửa đổi cho 'BValue'. Các hàm get/set/modify được định nghĩa một lần và forall cho mọi kiểu 'Lens a b'. (Xem bài đăng trên blog). Điều duy nhất còn lại cần làm là áp dụng, ví dụ, 'get' vào một ống kính cụ thể phù hợp với loại dữ liệu của bạn. Vì vậy: 'get piLens' là getter cho trường pi của' BValue'. – Lambdageek
Làm thế nào để sử dụng những người truy cập này trên một biến cụ thể của loại đã cho, ví dụ: 'bv :: BValue'? Ống kính áp dụng cho một loại, do đó, có thể 'get' hoặc' set' các trường của một biến thuộc loại đó. –
@mindbound chỉ áp dụng chức năng get/set/modify cho cả ống kính và giá trị: 'get piLens bv' hoặc' modify piLens (+ 1.0) bv' – Lambdageek