Nó thực sự chỉ là một hàm tạo dữ liệu bình thường được định nghĩa trong Prelude , là thư viện chuẩn được nhập tự động vào mọi mô-đun.
Có thể là gì, về mặt cấu trúc
Định nghĩa trông giống như sau:
data Maybe a = Just a
| Nothing
Khai báo đó xác định một kiểu, Maybe ađược tham số hóa bởi một biến kiểu a, điều này có nghĩa là bạn có thể sử dụng nó với bất kỳ kiểu nào thay cho a.
Xây dựng và Phá hủy
Kiểu có hai hàm tạo, Just avà Nothing. Khi một kiểu có nhiều hàm tạo, điều đó có nghĩa là một giá trị của kiểu phải được xây dựng chỉ với một trong các hàm tạo có thể. Đối với loại này, một giá trị được xây dựng thông qua Justhoặc Nothing, không có khả năng nào khác (không lỗi).
Vì Nothingkhông có kiểu tham số, khi nó được sử dụng như một phương thức khởi tạo, nó đặt tên cho một giá trị hằng số là thành viên của kiểu Maybe acho tất cả các kiểu a. Nhưng hàm Justtạo có tham số kiểu, có nghĩa là khi được sử dụng làm hàm tạo, nó hoạt động giống như một hàm từ kiểu asang Maybe a, tức là nó có kiểua -> Maybe a
Vì vậy, các hàm tạo của một kiểu xây dựng một giá trị của kiểu đó; mặt khác của vấn đề là khi nào bạn muốn sử dụng giá trị đó và đó là lúc kết hợp mẫu có tác dụng. Không giống như các hàm, các hàm tạo có thể được sử dụng trong các biểu thức ràng buộc mẫu và đây là cách mà bạn có thể thực hiện phân tích trường hợp các giá trị thuộc về các kiểu có nhiều hơn một hàm tạo.
Để sử dụng một Maybe agiá trị trong một đối sánh mẫu, bạn cần cung cấp một mẫu cho mỗi hàm tạo, như sau:
case maybeVal of
Nothing -> "There is nothing!"
Just val -> "There is a value, and it is " ++ (show val)
Trong biểu thức trường hợp đó, mẫu đầu tiên sẽ khớp nếu giá trị là Nothingvà mẫu thứ hai sẽ khớp nếu giá trị được tạo với Just. Nếu cái thứ hai khớp, nó cũng liên kết tên valvới tham số đã được chuyển cho hàm Justtạo khi giá trị mà bạn đang khớp với được tạo.
Có thể có nghĩa là gì
Có thể bạn đã quen với cách thức hoạt động của nó; thực sự không có bất kỳ phép thuật nào đối với Maybecác giá trị, nó chỉ là một Kiểu dữ liệu đại số Haskell (ADT) bình thường. Nhưng nó được sử dụng khá nhiều vì nó có hiệu quả "nâng" hoặc mở rộng một kiểu, chẳng hạn như Integertừ ví dụ của bạn, sang một ngữ cảnh mới trong đó nó có giá trị phụ ( Nothing) thể hiện sự thiếu giá trị! Các hệ thống kiểu sau đó yêu cầu bạn kiểm tra cho rằng giá trị tăng thêm trước khi nó sẽ cho phép bạn nhận được ở Integerđó có thể có mặt ở đó. Điều này ngăn chặn một số lỗi đáng chú ý.
Nhiều ngôn ngữ ngày nay xử lý loại giá trị "không có giá trị" này thông qua tham chiếu NULL. Tony Hoare, một nhà khoa học máy tính lỗi lạc (ông đã phát minh ra Quicksort và là người đoạt giải Turing), sở hữu điều này là "sai lầm tỷ đô la" của mình . Loại Có thể không phải là cách duy nhất để khắc phục điều này, nhưng nó đã được chứng minh là một cách hiệu quả để làm điều đó.
Có thể là một Functor
Ý tưởng chuyển đổi kiểu này sang kiểu khác sao cho các phép toán trên kiểu cũ cũng có thể được chuyển đổi để hoạt động trên kiểu mới là khái niệm đằng sau lớp kiểu Haskell được gọi Functor, Maybe acó một ví dụ hữu ích.
Functorcung cấp một phương thức được gọi là fmapánh xạ các hàm có phạm vi trên các giá trị từ kiểu cơ sở (chẳng hạn như Integer) đến các hàm có phạm vi trên các giá trị từ kiểu nâng lên (chẳng hạn như Maybe Integer). Một hàm được chuyển đổi với fmapđể hoạt động trên một Maybegiá trị hoạt động như sau:
case maybeVal of
Nothing -> Nothing -- there is nothing, so just return Nothing
Just val -> Just (f val) -- there is a value, so apply the function to it
Vì vậy, nếu bạn có một Maybe Integergiá trị m_xvà một Int -> Inthàm f, bạn có thể fmap f m_xáp dụng hàm ftrực tiếp cho hàm Maybe Integermà không cần lo lắng nếu nó thực sự có giá trị hay không. Trên thực tế, bạn có thể áp dụng toàn bộ chuỗi Integer -> Integerhàm nâng lên cho Maybe Integercác giá trị và chỉ phải lo lắng về việc kiểm tra rõ ràng Nothingmột lần khi bạn hoàn thành.
Có thể là một Đơn nguyên
Tôi không chắc bạn đã quen với khái niệm này như thế Monadnào, nhưng ít nhất bạn đã từng sử dụng IO atrước đây, và kiểu chữ ký IO atrông khá giống với Maybe a. Mặc dù IOđặc biệt ở chỗ nó không để lộ các hàm tạo của nó cho bạn và do đó chỉ có thể được "chạy" bởi hệ thống thời gian chạy Haskell, nó cũng vẫn là một yếu tố Functorbổ sung Monad. Trên thực tế, có một ý nghĩa quan trọng trong đó a Monadchỉ là một loại đặc biệt Functorvới một số tính năng bổ sung, nhưng đây không phải là nơi để đạt được điều đó.
Dù sao, Monads thích IOcác kiểu ánh xạ thành các kiểu mới đại diện cho "các phép tính dẫn đến giá trị" và bạn có thể nâng các hàm thành Monadcác kiểu thông qua một hàm rất fmapgiống được gọi là liftMbiến một hàm thông thường thành một "tính toán dẫn đến giá trị thu được bằng cách đánh giá chức năng."
Bạn có thể đã đoán ra (nếu bạn đã đọc đến đây) Maybecũng là một Monad. Nó đại diện cho "các phép tính không thể trả về giá trị". Cũng giống như với fmapví dụ, điều này cho phép bạn thực hiện toàn bộ các phép tính mà không cần phải kiểm tra lỗi rõ ràng sau mỗi bước. Và trên thực tế, cách Monadcá thể được xây dựng, việc tính toán trên Maybecác giá trị sẽ dừng ngay khi Nothinggặp phải, vì vậy nó giống như một sự hủy bỏ ngay lập tức hoặc một sự trở lại vô giá trị ở giữa một quá trình tính toán.
Bạn có thể đã viết có thể
Như tôi đã nói trước đây, không có gì cố hữu đối với Maybekiểu được đưa vào cú pháp ngôn ngữ hoặc hệ thống thời gian chạy. Nếu Haskell không cung cấp nó theo mặc định, bạn có thể tự cung cấp tất cả các chức năng của nó! Trên thực tế, bạn có thể tự mình viết lại nó, với các tên khác nhau và có cùng chức năng.
Hy vọng rằng bạn đã hiểu về Maybekiểu và các hàm tạo của nó, nhưng nếu vẫn còn điều gì chưa rõ, hãy cho tôi biết!
Maybenhững ngôn ngữ khác sẽ sử dụngnullhoặcnil(với những thứ khó chịuNullPointerExceptionẩn nấp trong mọi ngóc ngách). Bây giờ các ngôn ngữ khác cũng bắt đầu sử dụng cấu trúc này: Scala asOption, và ngay cả Java 8 cũng sẽ cóOptionalkiểu này.