2011-08-18 17 views
11

tôi có chức năng này trong Haskell:Tại sao các nhân viên bảo vệ không đầy đủ gây ra sự phù hợp với mô hình không thể chối cãi để thất bại?

test :: (Eq a) => a -> a -> Maybe a 
test a b 
    | a == b = Just a 
test _ _ = Nothing 

Đây là những gì tôi nhận được khi tôi đã thử các chức năng với các đầu vào khác nhau:

ghci>test 3 4 
Nothing 
ghci>test 3 3 
Just 3 

Theo Real World Haskell, mô hình đầu tiên là không thể chối cãi. Nhưng có vẻ như test 3 4 không làm hỏng mẫu đầu tiên và khớp với mẫu thứ hai. Tôi mong đợi một số loại lỗi - có thể là 'những người bảo vệ không đầy đủ'. Vì vậy, những gì đang thực sự xảy ra ở đây, và có cách nào để kích hoạt cảnh báo trình biên dịch trong trường hợp điều này vô tình xảy ra?

Trả lời

11

Các mô hình đầu tiên thực sự là một "mô hình không thể chối cãi", tuy nhiên điều này không có nghĩa là nó sẽ luôn luôn chọn mặt bên phải tương ứng của hàm của bạn. Nó vẫn còn tùy thuộc vào bảo vệ có thể thất bại như trong ví dụ của bạn.

Để đảm bảo tất cả các trường hợp đều được đề cập, việc sử dụng otherwise để bảo vệ cuối cùng sẽ luôn thành công.

test :: (Eq a) => a -> a -> Maybe a 
test a b 
    | a == b = Just a 
    | otherwise = Nothing 

Lưu ý rằng không có gì kỳ diệu về otherwise. Nó được định nghĩa trong Prelude là otherwise = True. Tuy nhiên, nó là thành ngữ để sử dụng otherwise cho trường hợp cuối cùng. Khi có một trình biên dịch cảnh báo về các bảo vệ không phải là exaustive sẽ là không thể trong trường hợp chung, vì nó sẽ liên quan đến việc giải quyết vấn đề tạm dừng, tuy nhiên có các công cụ như Catch mà cố gắng thực hiện công việc tốt hơn so với trình biên dịch. trường hợp được bảo hiểm hay không trong trường hợp phổ biến.

+1

Vì vậy, nếu đó là một mẫu không thể chối cãi, thì nó sẽ không khớp như thế nào? Có phù hợp phụ thuộc vào sự thành công của các vệ sĩ? Lần đầu tiên nó có khớp, và sau đó không khớp sau khi người bảo vệ không thành công? –

+4

@Matt: Mẫu thực sự khớp với nhau và bất kỳ biến nào bị ràng buộc bởi nó đều được cung cấp cho bảo vệ, điều này có thể không thành công. Khi điều này xảy ra, các lính canh còn lại được thử theo thứ tự. Nếu tất cả đều thất bại, mẫu tiếp theo sẽ được thử. Nếu không có thêm mẫu nào để thử, bạn sẽ gặp phải lỗi đối sánh mẫu không đầy đủ. – hammar

+4

Trong GHC 'nếu không' * là * đặc biệt. Nếu bạn tự mình định nghĩa nó, bạn sẽ kết thúc với các cảnh báo thời gian biên dịch khớp không đầy đủ (miễn là bạn cho phép các cảnh báo đó). – Rotsor

1

Các vệ sĩ không thể chối cãi. Nhưng là thực tế rất phổ biến (và tốt) để thêm một bảo vệ cuối cùng mà bắt các trường hợp khác, vì vậy chức năng của bạn trở thành:

test :: (Eq a) => a -> a -> Maybe a 
test a b 
    | a == b = Just a 
    | True = Nothing 
6

Trình biên dịch sẽ cảnh báo bạn nếu bạn bỏ qua mệnh đề thứ hai, tức là nếu trận đấu cuối cùng của bạn có một bộ đội bảo vệ, nơi trận đấu cuối cùng không phải là sự thật.

Nói chung, các nhân viên kiểm tra tính đầy đủ rõ ràng là không thể, vì nó sẽ khó giải quyết vấn đề dừng.

trả lời cho nhận xét của Matt:

Nhìn vào ví dụ:

foo a b 
    | a <= b = True 
    | a > b = False 

Một con người có thể thấy rằng một trong hai vệ sĩ phải đúng. Nhưng trình biên dịch không biết rằng a <= b hoặc a > b.

Bây giờ hãy tìm một ví dụ khác:

fermat a b c n 
    | a^n + b^n /= c^n = .... 
    | n < 0 = undefined 
    | n < 3 = .... 

Để chứng minh rằng tập hợp các vệ sĩ được hoàn tất, trình biên dịch phải chứng minh FLT. Nó không thể làm điều đó trong một trình biên dịch. Hãy nhớ rằng số lượng và độ phức tạp của các vệ sĩ không bị giới hạn. Trình biên dịch sẽ phải là một người giải quyết chung cho các vấn đề toán học, các vấn đề được nêu trong chính Haskell.

Nhiều chính thức, trong trường hợp đơn giản nhất:

f x | p x = y 

trình biên dịch phải chứng minh rằng nếu p x không phải là đáy, sau đó p xTrue cho tất cả các thể x. Nói cách khác, nó phải chứng minh rằng p x là dưới cùng (không dừng lại) bất kể số x là hoặc đánh giá là True.

+0

Bạn có thể giải thích thêm về lý do tại sao điều đó là không thể? Tôi quen thuộc với vấn đề dừng lại, nhưng không thấy tại sao điều này rõ ràng là không thể. –

+0

@Matt Tôi đã chỉnh sửa bài đăng của mình để trả lời câu hỏi của bạn. – Ingo

+0

Tôi thích ví dụ sử dụng [Định lý cuối cùng của Fermat] (http://en.wikipedia.org/wiki/Fermat%27s_Last_Theorem), là một trong những vấn đề nổi tiếng nhất trong toán học, và không được chứng minh cho đến năm 1995 (mặc dù Fermat tuyên bố có bằng chứng quá lớn để phù hợp với lề). – hammar

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