假设我写了以下代码:
一个游戏模块
module Game where
import Player
import Card
data Game = Game {p1 :: Player,
p2 :: Player,
isP1sTurn :: Bool
turnsLeft :: Int
}
一个播放器模块
module Player where
import Card
data Player = Player {score :: Int,
hand :: [Card],
deck :: [Card]
}
和一个卡片模块
module Card where
data Card = Card {name :: String, scoreValue :: Int}
然后我写了一些代码来实现逻辑,使玩家轮流从手牌中抽取和打出卡牌,以增加得分,直到游戏结束。
然而,完成这段代码后,我意识到我编写的游戏模块很无聊!
我想要重新设计这个纸牌游戏,使打出一张卡牌不仅仅是增加得分,而是任意改变游戏规则。
于是,我将Card
模块更改为以下内容:
module Card where
import Game
data Card = Card {name :: String,
onPlayFunction :: (Game -> Game)
scoreValue :: Int}
当然,这使得模块导入形成了一个循环。
我该如何解决这个问题?
简单的解决方案:
将所有文件移动到同一个模块中。这可以很好地解决问题,但会降低模块化程度;我以后无法在另一个游戏中重用相同的卡牌模块。
维护模块的解决方案:
向Card
添加一个类型参数:
module Card where
data Card a = {name :: String, onPlayFunc :: (a -> a), scoreValue :: Int}
为Player
添加另一个参数:
module Player where
data Player a {score :: Int, hand :: [card a], deck :: [card a]}
对于Game
,进行最后一次修改:
module Game where
data Game = Game {p1 :: Player Game,
p2 :: Player Game,
}
这保持了模块化,但需要我向我的数据类型添加参数。如果数据结构更深嵌套,我可能不得不向我的数据添加 - 很多 - 参数,如果我必须为多个解决方案使用此方法,我可能会得到数量繁杂的类型修饰符。
那么,有没有其他有用的解决方案来解决此重构问题,或者这些是唯一的两个选项?
{-# SOURCE #-}
/ .hs-boot 机制。 - leftaroundabout