2016-05-02 25 views
5

Hãy nói rằng tôi viết đoạn mã sau:Haskell - giải quyết mô-đun theo chu kỳ phụ thuộc

một trò chơi mô-đun

module Game where 
import Player 
import Card 
data Game = Game {p1 :: Player, 
        p2 :: Player, 
        isP1sTurn :: Bool 
        turnsLeft :: Int 
       } 

một cầu thủ mô-đun

module Player where 
import Card 
data Player = Player {score :: Int, 
         hand :: [Card], 
         deck :: [Card] 
        } 

và một mô-đun thẻ

module Card where 
data Card = Card {name :: String, scoreValue :: Int} 

Tôi sau đó viết một số cá tuyết e để thực hiện logic nơi người chơi thay phiên nhau vẽ và chơi bài từ tay của họ để thêm tiền thưởng vào điểm số của họ cho đến khi trò chơi hết lượt.

Tuy nhiên, tôi nhận ra sau khi hoàn thành mã này mà mô-đun trò chơi tôi đã viết là nhàm chán!

Tôi muốn cấu trúc lại thẻ trò chơi để khi bạn chơi bài, thay vì chỉ thêm điểm số, thay vào đó thẻ tự ý chuyển đổi trò chơi.

Vì vậy, tôi thay đổi các mô-đun Card như sau

module Card where 
import Game 
data Card = Card {name :: String, 
        onPlayFunction :: (Game -> Game)    
        scoreValue :: Int} 

trong đó tất nhiên làm cho nhập khẩu mô-đun tạo thành một chu kỳ.

Làm cách nào để giải quyết vấn đề này?

Giải pháp tầm thường:

Di chuyển tất cả các tệp sang cùng một mô-đun. Điều này giải quyết vấn đề một cách độc đáo, nhưng giảm mô đun; Sau này tôi không thể sử dụng lại cùng một mô-đun thẻ cho một trò chơi khác.

Mô-đun giải pháp duy trì:

Thêm một tham số kiểu để Card:

module Card where 
data Card a = {name :: String, onPlayFunc :: (a -> a), scoreValue :: Int} 

Thêm tham số khác để Player:

module Player where 
data Player a {score :: Int, hand :: [card a], deck :: [card a]} 

Với một sửa đổi cuối cùng để Game:

module Game where 
data Game = Game {p1 :: Player Game, 
        p2 :: Player Game, 
       } 

Điều này giúp duy trì mô đun, nhưng yêu cầu tôi phải thêm thông số vào các loại dữ liệu của mình. Nếu các cấu trúc dữ liệu được lồng sâu hơn, tôi có thể phải thêm nhiều tham số vào dữ liệu của mình và nếu tôi phải sử dụng phương thức này cho nhiều giải pháp, tôi có thể kết thúc với một số lượng biến đổi kiểu khó sử dụng.

Vì vậy, có bất kỳ giải pháp hữu ích nào khác để giải quyết trình tinh chỉnh này hay không hoặc chỉ là hai tùy chọn này?

Trả lời

6

Giải pháp của bạn (thêm thông số loại) không phải là thông số xấu.loại của bạn trở thành tổng quát hơn (bạn có thể sử dụng Card OtherGame nếu bạn cần nó), nhưng nếu bạn không thích các thông số thêm bạn có thể một trong hai:

  • viết một module CardGame có chứa (chỉ) kiểu dữ liệu lẫn nhau đệ quy của bạn, và nhập này mô-đun trong những người khác, hoặc
  • trong ghc, sử dụng {-# SOURCE #-} pragmas để break the circular dependency

giải pháp cuối cùng này yêu cầu bằng văn bản của một tập tin Card.hs-boot với một tập hợp các tờ khai gõ Card.hs.

+3

Tôi thực sự khuyên bạn nên tránh cơ chế '{- # SOURCE # -}'/.hs-boot, trừ khi nó thực sự cần thiết. – leftaroundabout

+1

@leftroundabout: Vâng, tôi thấy nó khó sử dụng và không thoải mái, nhưng có bất kỳ lý lẽ nào chống lại nó hơn những cái được đề cập trong [wiki] (https://wiki.haskell.org/Mutually_recursive_modules), là (imho) không có liên quan đến các dự án nhỏ? –

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