Скажем, я пишу следующий код:Haskell - разрешение циклического модуля зависимость
игровой модуль
module Player where
import Card
data Player = Player {score :: Int,
hand :: [Card],
deck :: [Card]
}
модуль
module Game where
import Player
import Card
data Game = Game {p1 :: Player,
p2 :: Player,
isP1sTurn :: Bool
turnsLeft :: Int
}
игрок и модуль карты
module Card where
data Card = Card {name :: String, scoreValue :: Int}
Затем я пишу какую-нибудь треску e для реализации логики, когда игроки по очереди рисуют и играют в карты из своей руки, чтобы добавить бонусы к их счету, пока игра не закончится.
Однако после завершения этого кода я понял, что игровой модуль, который я написал, скучен!
Я хочу реорганизовать карточную игру, поэтому, когда вы играете на карточке, а не просто добавляете счет, вместо этого карта произвольно преобразует игру.
Итак, я изменяю Card
модуль к следующему
module Card where
import Game
data Card = Card {name :: String,
onPlayFunction :: (Game -> Game)
scoreValue :: Int}
, который, конечно, делает импорт модулей образуют цикл.
Как решить эту проблему?
Trivial Решение:
Переместить все файлы в одном модуле. Это хорошо решает проблему, но снижает модульность; Я не могу повторно использовать один и тот же модуль карты для другой игры.
Модуль решение поддержания:
Добавить параметр типа в 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
@leftroundabout: Да, я нахожу это неудобным и неудобным, но есть ли какие-либо аргументы против него, чем те, которые упомянуты в [wiki] (https://wiki.haskell.org/Mutually_recursive_modules), которые (imho) не столь актуальным для небольших проектов? –