2015-12-03 12 views
8

Vì vậy, tôi đã bận rộn với cuốn sách Real World Haskell và tôi đã thực hiện bài tập lastButOne. Tôi đã đưa ra 2 giải pháp, một với mô hình phù hợp vớiMột ví dụ thực tế khi mô hình phù hợp là thích hợp hơn so với một biểu hiện trường hợp trong Haskell?

lastButOne :: [a] -> a 
lastButOne ([]) = error "Empty List" 
lastButOne (x:[]) = error "Only one element" 
lastButOne (x:[x2]) = x 
lastButOne (x:xs) = lastButOne xs 

Và một sử dụng một biểu thức trường hợp

lastButOneCase :: [a] -> a 
lastButOneCase x = 
    case x of 
    [] -> error "Empty List" 
    (x:[]) -> error "Only One Element" 
    (x:[x2]) -> x 
    (x:xs) -> lastButOneCase xs 

Những gì tôi muốn tìm hiểu là khi khớp mẫu sẽ được ưa thích hơn biểu thức dạng chữ và ngược lại. Ví dụ này không đủ tốt đối với tôi bởi vì có vẻ như trong khi cả hai chức năng hoạt động như dự định, nó không đưa tôi chọn một triển khai thực hiện hơn cái kia. Vì vậy, sự lựa chọn "có vẻ" ưu tiên ở cái nhìn đầu tiên? Vì vậy, có trường hợp tốt bằng phương tiện của mã nguồn, hoặc trong nguồn riêng của haskell hoặc github hoặc ở một nơi khác, nơi mà người ta có thể nhìn thấy khi một trong hai phương pháp được ưa thích hay không? Không.

+5

Tôi thích cái ngắn hơn hai dòng. – Bergi

+8

Các biểu thức trường hợp không sử dụng cùng một mẫu phù hợp, chỉ trong một cấu trúc cú pháp khác nhau? – 9000

+3

Biểu thức trường hợp có thể được nhúng vào một biểu thức khác, không nhất thiết phải là biểu thức đầu tiên của định nghĩa hàm. Tôi cho rằng các khai báo nhiều hàm với các mẫu chỉ là một đường cú pháp trên biểu mẫu thứ hai. – 9000

Trả lời

15

Đầu tiên là một thuật ngữ ngắn hạn: Tôi sẽ gọi cả hai "mẫu phù hợp" này. Tôi không chắc rằng có một thuật ngữ tốt để phân biệt kiểu trùng khớp theo trường hợp và mẫu phù hợp-qua-nhiều định nghĩa.

Sự khác biệt về mặt kỹ thuật giữa hai loại này thực sự khá nhẹ. Bạn có thể tự xác minh điều này bằng cách yêu cầu GHC đổ lõi mà nó tạo ra cho hai hàm, sử dụng cờ -ddump-simpl. Tôi đã thử điều này ở một vài mức tối ưu khác nhau, và trong mọi trường hợp, sự khác biệt duy nhất trong Core là đặt tên. (Nhân tiện, nếu có ai biết chương trình "khác biệt ngữ nghĩa" tốt cho Core - mà biết về ít nhất là tương đương alpha - Tôi rất thích nghe về nó!)

Có một vài nhỏ gotchas để xem ra cho, mặc dù. Bạn có thể tự hỏi liệu những điều sau đây cũng tương đương:

{-# LANGUAGE LambdaCase #-} 
lastButOne = \case 
    [] -> error "Empty List" 
    (x:[]) -> error "Only One Element" 
    (x:[x2]) -> x 
    (x:xs) -> lastButOneCase xs 

Trong trường hợp này, câu trả lời là có. Nhưng xem xét việc này tương tự như nhìn một:

-- ambiguous type error 
sort = \case 
    [] -> [] 
    x:xs -> insert x (sort xs) 

Đột nhiên đây là một CAF typeclass-đa hình, và vân vân GHCs cũ này sẽ kích hoạt những hạn chế monomorphism và gây ra lỗi, trong khi phiên bản một cách hời hợt giống hệt với một Lập luận rõ ràng không:

-- this is fine! 
sort [] = [] 
sort (x:xs) = insert x (sort xs) 

sự khác biệt nhỏ khác (mà tôi quên mất - cảm ơn bạn đã nhắc nhở tôi Thomas DuBuisson) là trong việc xử lý các khoản nơi. Vì các mệnh đề được gắn vào các trang liên kết, chúng không thể được chia sẻ trên nhiều phương trình nhưng có thể được chia sẻ qua nhiều trường hợp.Ví dụ:

-- error; the where clause attaches to the second equation, so 
-- empty is not in scope in the first equation 
null [] = empty 
null (x:xs) = nonempty 
    where empty = True 
     nonempty = False 

-- ok; the where clause attaches to the equation, so both empty 
-- and nonempty are in scope for the entire case expression 
null x = case x of 
    [] -> empty 
    x:xs -> nonempty 
    where 
    empty = True 
    nonempty = False 

Bạn có thể nghĩ điều này có nghĩa bạn có thể làm điều gì đó với phương trình mà bạn không thể làm với trường hợp biểu thức, cụ thể là, có ý nghĩa khác nhau đối với cùng tên trong hai phương trình, như thế này:

null [] = answer where answer = True 
null (x:xs) = answer where answer = False 

Tuy nhiên, kể từ khi mô hình của case biểu là các trang web liên kết, điều này có thể được mô phỏng trong case biểu thức cũng như:

null x = case x of 
    [] -> answer where answer = True 
    x:xs -> answer where answer = False 

Cho dù mệnh đề where được gắn vào mẫu của case hay phương trình phụ thuộc vào thụt đầu dòng, tất nhiên.

+4

"Tôi không chắc chắn có một thuật ngữ tốt để phân biệt mẫu phù hợp-qua-trường hợp và mô hình phù hợp-qua-nhiều định nghĩa." [Giấy tờ Hudak, Hughes, Peyton Jones và Wadler về lịch sử của Haskell] (http://haskell.cs.yale.edu/wp-content/uploads/2011/02/history.pdf) gọi đây là "kiểu khai báo" (cho nhiều phương trình) so với "kiểu biểu thức" (cho biểu thức 'trường hợp'). –

+0

Câu trả lời hay! Tôi cho một người không biết rằng bạn có thể có 'ràng buộc' ở chân của một' trường hợp '. –

4

Nếu tôi nhớ chính xác cả hai điều này sẽ "desugar" vào cùng một mã lõi trong ghc, do đó, lựa chọn hoàn toàn là phong cách. Cá nhân tôi sẽ đi cho người đầu tiên. Như ai đó đã nói, ngắn hơn của nó, và những gì bạn hạn "phù hợp với mô hình" được dự định sẽ được sử dụng theo cách này. (Trên thực tế phiên bản thứ hai cũng phù hợp với mẫu, chỉ cần sử dụng một cú pháp khác cho nó).

1

Đó là tùy chọn phong cách. Một số người đôi khi cho rằng lựa chọn này hay lựa chọn khác làm cho những thay đổi mã nhất định tốn ít nỗ lực hơn, nhưng tôi thường tìm ra những lập luận như vậy, ngay cả khi chính xác, không thực sự có một sự cải thiện lớn. Vì vậy, làm như bạn muốn.

Một góc độ đáng để đưa vào đây là giấy của Hudak, Hughes, Peyton Jones và Wadler "A History of Haskell: Being Lazy With Class". Phần 4.4 là về chủ đề này. Câu chuyện ngắn: Haskell hỗ trợ cả bởi vì các nhà thiết kế không thể đồng ý với nhau. Yep, một lần nữa, đó là một sở thích phong cách.

0

Khi bạn đang đối sánh trên nhiều hơn một biểu thức, case bắt đầu trông hấp dẫn hơn.

f pat11 pat21 = ... 
f pat11 pat22 = ... 
f pat11 pat23 = ... 
f pat12 pat24 = ... 
f pat12 pat25 = ... 

có thể gây phiền nhiễu hơn để viết hơn

f pat11 y = 
    case y of 
    pat21 -> ... 
    pat22 -> ... 
    pat23 -> ... 
f pat12 y = 
    case y of 
    pat24 -> ... 
    pat25 -> ... 

Quan trọng hơn, tôi đã phát hiện ra rằng khi sử dụng GADTs, các "tuyên bố phong cách" dường như không tuyên truyền bằng chứng từ trái sang phải theo cách tôi mong đợi. Có thể có một số mẹo tôi đã không làm việc ra, nhưng tôi cuối cùng phải tổ chức biểu thức case để tránh cảnh báo mẫu không hoàn chỉnh giả mạo.

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