2014-11-01 31 views
5

Tôi đang làm việc trên một số mã cho một trò chơi thẻ:Có phải viết các hàm trợ giúp cho trạng thái chuyển thành kiểu trạng thái trong Haskell không?

splitCards_ (x:xs) (a,b,c) | isGold x = splitCards xs (a:x,b,c) 
          | isAction x = splitCards xs (a,b:x,c) 
          | isVP x  = splitCards xs (a,b,c:x) 
splitCards_ [] (a,b,c) = (a,b,c) 

splitCards xs = splitCards_ xs ([],[],[]) 

Về cơ bản, lấy một danh sách các thẻ, và tách nó thành ba danh sách khác nhau tùy thuộc vào loại thẻ. splitCards_ đại diện cho cập nhật trạng thái bằng cách đệ quy cập nhật thông số của nó, sau đó splitCards (chức năng thực tế) được sử dụng để luôn bắt đầu tính toán với ba danh sách loại thẻ cụ thể trống.

Tôi tin rằng đây được gọi là trạng thái chuyển giao, và tôi khá chắc chắn đó là thành ngữ hoàn hảo, nhưng tôi quan tâm hơn đến thực tế là tôi phải xác định hàm trợ giúp splitCards_ để làm việc này theo cách tôi muốn. Tạo các hàm trợ giúp như Haskell thành ngữ này? Có một cách sạch hơn để viết này? Có quy ước đặt tên nào thích hợp hơn để chỉ đặt dấu gạch dưới vào cuối tên của hàm trợ giúp không?

Trả lời

8

Vâng, đây là một phong cách thành ngữ hoàn hảo. Đó là một cách cổ điển để làm cho một hàm đuôi đệ quy. (Mặc dù điều đó ít quan trọng và hơi sắc thái hơn trong Haskell).

Hơn nữa, việc tạo các hàm trợ giúp chắc chắn là tốt và một phần quan trọng của nhiều mẫu phổ biến. Nếu bạn cảm thấy rằng một cái gì đó là tự nhiên hơn yếu tố ra, đi cho nó! Trừ khi nó được đưa đến một cực đoan, nó giúp dễ đọc.

Đề xuất chính tôi đã đặt hàm trợ giúp vào một mệnh đề where. Bằng cách này, nó sẽ chỉ được hiển thị trong phạm vi của chức năng chính mà làm cho nó rõ ràng rằng nó chỉ là một người trợ giúp. Tên bạn cung cấp cho hàm trợ giúp là ít quan trọng hơn; splitCards_ là tốt, nhưng splitCards' (phát âm là "splitCards prime") và go (tên chung cho các hàm trợ giúp) sẽ phổ biến hơn. Vì vậy, tôi sẽ viết lại một cái gì đó mã của bạn như thế này:

splitCards xs = go xs ([],[],[]) 
    where go (x:xs) (a, b, c) | isGold x = go xs (a:x,b,c) 
          | isAction x = go xs (a,b:x,c) 
          | isVP x  = go xs (a,b,c:x) 
     go [] (a, b, c) = (a, b, c) 

Lưu ý rằng đây là những thay đổi-gì vừa mỹ phẩm bạn đang làm là cơ bản âm thanh.

Hai tùy chọn đặt tên (gosplitCards') chỉ là vấn đề ưu tiên.

Cá nhân tôi thích go bởi vì, khi bạn đã quen với quy ước, nó rõ ràng báo hiệu rằng một điều gì đó chỉ là một hàm trợ giúp. Theo một nghĩa nào đó, go gần giống cú pháp hơn là một hàm của riêng nó; ý nghĩa của nó hoàn toàn phụ thuộc vào hàm splitCards.

Những người khác không thích go vì nó hơi khó hiểu và có phần tùy ý. Nó cũng có thể làm cho cấu trúc đệ quy của mã của bạn ít rõ ràng hơn vì bạn đang đệ quy trên go và không phải là chính hàm đó.

Tìm mọi thứ bạn cho là đẹp nhất.

3

Tôi không có gì nhiều để thêm vào @ câu trả lời Tikhon của ngoại trừ trong trường hợp cụ thể này, bạn có thể sử dụng partition chức năng từ Data.List:

splitCards xs = 
    let (as,bs) = partition isGold xs 
     (cs,ds) = partition isAction bs 
    in (as,cs,ds) -- (golds, actions, others) 

Do lười biếng đánh giá nó nên có về cơ bản hiệu năng giống như bàn tay của bạn phiên bản thủ công.

1

Trong trường hợp chung, mã của bạn là thành ngữ, đặc biệt nếu được làm sạch một chút như @Tikhon đề xuất. Trong trường hợp cụ thể, sơ đồ đệ quy của bạn dường như là một nếp gấp trái, do đó, nó thường được làm rõ ràng trong mã. Xây dựng dựa trên @ đang Tikhon của:

splitCards xs = foldl' separate ([],[],[]) xs 
    where separate (a, b, c) x | isGold x = (a:x,b,c) 
          | isAction x = (a,b:x,c) 
          | isVP x  = (a,b,c:x) 

Dòng đầu tiên thậm chí có thể được eta-ký hợp đồng (không cần thiết trong trường hợp này, IMHO, nhưng ...)

splitCards = foldl' separate ([],[],[]) 
    where ... 
Các vấn đề liên quan