2010-05-06 6 views
10

Tôi mới bắt đầu Haskell, nhưng từ tất cả các hướng dẫn trực tuyến tôi thấy tôi dường như không thể tìm thấy nếu có một cách được chấp nhận để thực hiện một câu lệnh điều khiển có điều kiện. Tôi đã thấy nếu người khác, bảo vệ, và phù hợp với mô hình, nhưng tất cả họ dường như hoàn thành cùng một điều. Có cách nào thường được chấp nhận/nhanh hơn/hiệu quả hơn so với phần còn lại?Câu lệnh điều khiển trong Haskell?

+2

Đừng quên 'case-of' :) – kennytm

+1

' case' là đối sánh mẫu. – Chuck

+4

Tất cả các kỹ thuật đó đều được biên dịch thành 'case'. 'case' là cơ chế điều khiển cơ bản - điều phối dựa trên một mẫu. Các lính canh, các mẫu vân vân vân vân chỉ là đường. –

Trả lời

10

Có cách nào thường được chấp nhận/nhanh hơn/hiệu quả hơn so với phần còn lại?

Các đường dẫn là đường cú pháp (khá phức tạp) nếu có sau khi so khớp mẫu. Nếu-thì-else là cú pháp đường cho case trên Bool. Vì vậy, những điều này hầu như không kém phần hiệu quả.

Nhưng đây là một quan sát: thường dễ dàng thực hiện không hiệu quả với biểu thức Boolean là gì hiệu quả với đối sánh mẫu. Một ví dụ điển yêu thích của các lập trình viên đầu Haskell là viết

length xs == 0 

mà chi phí tỷ lệ thuận với độ dài của xs, nơi

case xs of { [] -> True; _:_ -> False } 

tốn thời gian liên tục.

Một cách chính xác hơn để quan sát những gì đang xảy ra là (phần mở rộng lạ mắt vắng mặt như xem mẫu), chi phí trường hợp xấu nhất của một mô hình phù hợp là tỷ lệ thuận với số lượng nhà xây dựng xuất hiện ở phía bên trái — bạn chỉ không thể viết một mẫu phù hợp với cả đắt tiền và nhỏ. Ngược lại, kích thước của biểu thức Boolean cho bạn biết không có gì về chi phí để đánh giá nó. Trong ý nghĩa này, và theo nghĩa này, mô hình phù hợp là rẻ hơn so với nếu-thì-khác hoặc bảo vệ.

Thuyết minh tốt cho người mới bắt đầu là sử dụng mẫu phù hợp với bất cứ nơi nào bạn có thể có thể. Khi bạn có thêm kinh nghiệm, bạn có thể tinh chỉnh cách tiếp cận của mình.

+0

(Tất nhiên, bạn nên sử dụng 'null xs' để kiểm tra xem' xs' có rỗng không.) – kennytm

+1

@Kenny Nếu tôi có một đô la cho mỗi sinh viên của tôi, người đã viết 'length xs == 0' thay vì' null xs' , Tôi sẽ có đủ để giữ cho tôi trong cà phê trong năm :-) –

4

Vâng, tôi không biết nếu suy nghĩ về "điều khiển báo cáo" là cách tốt nhất để đi về nó trong Haskell. Điều đó nói rằng, nó chủ yếu là tất cả đi xuống để phù hợp với mô hình cuối cùng; các điều kiện boolean chẳng hạn như if ... then ... else có thể được xác định theo kiểu khớp mẫu trên các hàm tạo cho ví dụ Bool.

Dạng "nguyên thủy" nhất có lẽ là câu lệnh case - đối sánh mẫu cho định nghĩa hàm chỉ là cú pháp cú pháp trên một định nghĩa hàm duy nhất chứa một biểu thức lớn case.

Về mặt những gì bạn nên sử dụng, hãy làm theo bất kỳ điều gì có ý nghĩa nhất về mặt khái niệm. Kết hợp mẫu phù hợp nhất khi bạn cần tách rời một kiểu dữ liệu đại số; Các khối if thích hợp khi bạn cần một kết quả có/không đơn giản cho một số biến vị ngữ. Các vệ sĩ thường được sử dụng khi bạn cần một hỗn hợp của việc giải mã kiểu dữ liệu và các biến vị ngữ boolean.

Điểm quan trọng nhất cần nhớ là đối sánh mẫu là cách duy nhất để tách rời loại dữ liệu đại số. Các biến vị ngữ Boolean có thể dễ dàng replaced with higher-order functions, nhưng việc trích xuất các giá trị bên trong một hàm tạo dữ liệu yêu cầu khớp mẫu.

4

Không một trong ba tùy chọn thực hiện chính xác điều tương tự hoặc có thể được sử dụng trong mọi tình huống.

Đối sánh mẫu kiểm tra xem hàm tạo nào được sử dụng để tạo một giá trị nhất định và chúng liên kết các biến. Cả người bảo vệ cũng không làm vậy. Bạn chỉ có thể sử dụng chúng thay vì các mẫu phù hợp nếu bạn khớp với một hàm tạo null (hoặc một chữ số) của một kiểu thực thi Eq.

Ví dụ:

foo (Just x) = x+1 -- Can not do this without a pattern match (except by using 
        -- functions like fromJust that themselves use pattern matches) 
foo Nothing = 0 -- You could do this using a pattern guards like 
       -- foo x | x==Nothing = 0, but that is less readable and less 
       -- concise than using a plain pattern match 

lính gác Pattern cho phép bạn kiểm tra những thứ khác hơn là bình đẳng. Ví dụ. bạn có thể kiểm tra xem một số đã cho có lớn hơn không. Tất nhiên bạn có thể làm điều tương tự với nếu, nhưng bảo vệ mô hình cho phép bạn đi đến các mô hình tiếp theo khi một bảo vệ không thành công, có thể dẫn đến sự lặp lại ít hơn bằng cách sử dụng nếu. Ví dụ:

maybeSqrt (Just x) | x >= 0 = sqrt x 
maybeSqrt _ = Nothing 

Sử dụng nếu điều này sẽ trông như thế này (lưu ý sự lặp lại của Nothing):

maybeSqrt (Just x) = if x >= 0 then sqrt x 
        else Nothing 
maybeSqrt _ = Nothing 

Cuối cùng nếu có thể được sử dụng mà không cần mô hình phù hợp. Nếu bạn không thực sự sử dụng mẫu phù hợp trên một giá trị nhất định giới thiệu một case x of ... chỉ để bạn có thể sử dụng mô hình bảo vệ làm cho ít ý nghĩa và ít có thể đọc được và súc tích hơn chỉ sử dụng nếu.

2

Tôi chọn dựa trên những gì làm cho mã trông đẹp hơn và dễ đọc hơn. Như @Don chỉ ra, nhiều dạng khác nhau này được biên dịch thành case. Chúng trông khác nhau vì đường cú pháp có sẵn. Đường này không dành cho trình biên dịch, nó dành cho con người. Vì vậy, quyết định dựa trên những gì bạn nghĩ rằng những người khác muốn đọc, và những gì có thể đọc được cho bạn.