2011-12-10 40 views
13

Tôi đã tạo một chức năng mà tôi có thể sử dụng (theo như tôi biết) biểu thức hoặc bảo vệ trường hợp.Phương pháp nào ưu tiên để viết "bảo vệ"?

foo a b c = case a of 1 -> [...] 
         2 -> [...] 
         3 -> [...] 
         [...] 
         otherwise -> error "..." 

hoặc

foo a b c | a == 1 = [...] 
      | a == 2 = [...] 
      | a == 3 = [...] 
      | [...] 
      | otherwise = error "..." 

Vì vậy, câu hỏi là: có những 2 (trường hợp hoặc bảo vệ) là “tốt hơn” mã hóa? Về cơ bản có giống nhau không?

+10

Trong ví dụ đầu tiên của bạn, bạn không nên sử dụng 'nếu không' như thế. Những gì nó làm là nó sẽ giới thiệu một biến mới gọi là 'else = a', có thể dẫn đến lỗi tinh tế. Bạn nên làm '_ -> lỗi" ... "' thay thế. – dflemstr

+0

@dflemstr cảm ơn thông tin và giải thích. – Nomics

+1

Là mẹo chung về ngôn ngữ chung, tôi thích viết các mã con trên mã tiếp theo và luôn có cùng mức thụt đầu dòng. Điều này bảo vệ bạn khỏi phải liên kết lại các dòng còn lại nếu đầu tiên thay đổi chiều dài (có lẽ do foo đang được đổi tên hoặc dòng nào đó) – hugomg

Trả lời

13

Kiểu đầu tiên được coi là kiểu tốt hơn, vì 2 lý do.

Trước hết: Nhiều người sẽ nói rằng có vẻ tốt hơn, vì bạn không phải nhập tất cả các số ==. Đây là một lý do rất chủ quan, tất nhiên. Ngoài ra, bạn sẽ thường thậm chí không đưa ra một tuyên bố trường hợp mới, nhưng chỉ phù hợp với các đối số trong danh sách đối số chức năng như vậy:

foo 1 b c = ... -- etc 
... 
foo _ b c = ... -- for the "otherwise" part 

Điều này làm cho mã thậm chí nhỏ gọn hơn và dễ đọc, mà nhiều người thích.

Thứ hai, thực sự có sự khác biệt ngữ nghĩa. Hãy tưởng tượng rằng bạn có một kiểu dữ liệu như thế này:

data Cake = Apple | Cheese | Cream 

Nếu bạn sử dụng phương pháp đầu tiên, bạn kết hợp với các nhà thầu trong biểu thức case..of:

case a of 
    Apple -> "fruit" 
    _  -> "not fruit" 

Tuy nhiên, nếu bạn cố gắng làm một bảo vệ biểu hiện của một số loại, như thế này:

| a == Apple = "fruit" 
| otherwise = "not fruit" 

... nó sẽ không thực sự làm việc, bởi vì loại Cake không có một thể hiện Eq, do đó bạn không thể sử dụng == để so sánh hai giá trị. Giới thiệu một cá thể Eq (với deriving (Eq) sau khi định nghĩa dữ liệu) không phải lúc nào cũng muốn, do đó không phải thực hiện trong trường hợp này có thể là đáng kể.

+0

Làm thế nào bạn có thể nói một cái tốt hơn cái kia nếu chúng khác nhau về mặt ngữ nghĩa? –

+1

@AdamWagner vì trong nhiều trường hợp, bạn có tùy chọn để sử dụng một trong hai kết quả chính xác giống nhau (bằng cách "so sánh mã máy kết quả"). – dflemstr

+0

Vấn đề ngữ nghĩa là mới đối với tôi! Suy nghĩ thấu đáo!! O_o – Nomics

9

Khi bảo vệ có thể được viết lại dưới dạng tuyên bố trường hợp (không bảo vệ) trên một trong các tham số, nó không thực sự cần thiết. I E. bạn chỉ có thể viết như sau:

foo 1 b c = [...] 
foo 2 b c = [...] 
foo 3 b c = [...] 
[...] 

Cách nào ưu tiên để viết. Bạn sẽ sử dụng bảo vệ khi điều kiện bạn muốn không thể được thể hiện dưới dạng mẫu. Và bạn sẽ sử dụng câu lệnh khi bạn cần khớp với một thứ khác với một trong các tham số.

+0

Thực ra, tôi có một số trường hợp cơ bản (Tôi tin rằng tôi có thể gọi chúng là trường hợp cơ sở) người mới bắt đầu viết mã), như “if a == 1 && b> c rồi (...)”. Vì vậy, nếu áp dụng đề xuất của bạn, nó có thể làm cho mã của tôi một chút ít có thể đọc được, tôi đoán (?). – Nomics

+0

Thực ra (phần 2) ... Tôi yêu tôi có thể đề xuất ý kiến ​​của bạn ... và có vẻ tốt! ^^ – Nomics

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