2015-01-14 42 views
26

Tôi phải học Haskell cho trường đại học và tôi đang sử dụng learnyouahaskell.com để bắt đầu.
Tôi luôn sử dụng các ngôn ngữ bắt buộc nên tôi quyết định thực hành Haskell bằng cách viết mã nhiều hơn những ngôn ngữ khác.
tôi bắt đầu để thực hiện một số chức năng để làm việc với các danh sách như head, tail, init ...
Tại một số điểm tôi nhìn lên việc triển khai của các chức năng này để so sánh với tôi và tôi stumbled khi các chức năng vô quy định tại List.lhs . thực hiệnThực hiện chức năng null

của null:

-- | Test whether a list is empty. 
null     :: [a] -> Bool 
null []     = True 
null (_:_)    = False 

thực hiện của tôi:

mNull :: [a] -> Bool 
mNull []  = True 
mNull _   = False 

Tôi biết không có câu hỏi ngu ngốc ngay cả đối với những câu hỏi đơn giản như vậy :)
Vì vậy, câu hỏi của tôi là tại sao những ứng dụng thực hiện ban đầu (_:_) thay vì chỉ _?
Có lợi thế nào khi sử dụng (_:_) hoặc có bất kỳ trường hợp cạnh nào mà tôi không biết?
Tôi thực sự không thể tưởng tượng được bất kỳ lợi thế nào vì _ bắt mọi thứ.

+4

Chúng thực sự bình đẳng, tôi cũng thấy nó ngớ ngẩn. Tôi đoán là tác giả muốn rõ ràng. – MasterMastic

Trả lời

39

Bạn có thể không chỉ cần bật các điều khoản xung quanh với giải pháp của bạn:

mNull' :: [a] -> Bool 
mNull' _ = False 
mNull' [] = True 

sẽ luôn năng suất False này, ngay cả khi bạn vượt qua một danh sách trống. Bởi vì thời gian chạy không bao giờ xem xét mệnh đề [], nó ngay lập tức thấy _ khớp với bất kỳ điều gì. (GHC sẽ cảnh báo bạn về một mô hình chồng chéo như vậy.)

Mặt khác,

null' :: [a] -> Bool 
null' (_:_) = False 
null' [] = True 

vẫn hoạt động một cách chính xác, bởi vì (_:_) không phù hợp với trường hợp cụ thể của một danh sách trống.

Chính điều đó không thực sự cho hai mệnh đề rõ ràng là một lợi thế. Tuy nhiên, trong mã phức tạp hơn, viết ra tất cả các tùy chọn ngoại lệ lẫn nhau có một lợi ích: nếu bạn đã quên một tùy chọn, trình biên dịch cũng có thể cảnh báo bạn về điều đó! Trong khi đó, _ có thể và sẽ chỉ xử lý mọi trường hợp không được xử lý bởi các điều khoản trước đó, ngay cả khi điều đó không thực sự chính xác.

+0

Có ai có ý tưởng tại sao bài đăng này vô cùng phổ biến không? – leftaroundabout

6

_ nghĩa đen là bất kỳ thứ gì ngoài các mẫu được chỉ định rõ ràng. Khi bạn chỉ định (_:_), điều này có nghĩa là bất kỳ thứ gì có thể được biểu diễn dưới dạng danh sách chứa ít nhất 1 phần tử, mà không làm phiền đến những gì hoặc thậm chí bao nhiêu phần tử trong danh sách thực sự chứa. Vì trường hợp có mẫu rõ ràng cho danh sách trống đã có, (_:_) cũng có thể được thay thế bằng _.

Tuy nhiên, đại diện cho nó là (_:_) mang lại cho bạn sự linh hoạt để thậm chí không rõ ràng chuyển mẫu danh sách trống. Trong thực tế, điều này sẽ làm việc:

-- | Test whether a list is empty. 
null     :: [a] -> Bool  
null (_:_)    = False 
null _     = True 

Demo

4

Tôi sẽ thêm vào những gì còn sót lại nói. Đây không thực sự là một mối quan tâm tiềm năng đối với loại danh sách, nhưng nói chung, các kiểu dữ liệu đôi khi được sửa đổi. Nếu bạn có một vô hình thành

data FavoriteFood = Pizza 
        | SesameSpinachPancake 
        | ChanaMasala 

và sau đó bạn học cách thích DrunkenNoodles và thêm nó vào danh sách, tất cả các chức năng của bạn mà mô hình trận đấu vào loại sẽ cần phải được mở rộng. Nếu bạn đã sử dụng bất kỳ mẫu _ nào, bạn sẽ cần tìm chúng theo cách thủ công; trình biên dịch không thể giúp bạn. Nếu bạn đã đối sánh từng điều một cách rõ ràng, bạn có thể bật -fwarn-incomplete-patterns và GHC sẽ cho bạn biết về mọi điểm bạn đã bỏ lỡ.

Các vấn đề liên quan