我正在寻找以下代码的一些重构/最佳实践建议。我想尝试避免扩展,同时为不同的“版本”维护单独的模块,这些模块是互斥的。我目前的解决方案是使用一个类并使用存在量化为每个CountrySets
创建一个公共类型。
如果我使用OOP,这对我来说很容易实现,但我不能认为它是“功能性的”。
感谢您的时间。
Province.hs
{-# LANGUAGE ExistentialQuantification, RankNTypes #-}
module Province where
class Country a where
--some stuff that is not important
data Power =
forall a. (Show a, Eq a, Country a) => Power a |
Netural |
Water
data Unit = Unit {
power :: forall a. (Show a, Eq a, Country a) => a,
piece :: Piece
data Piece = Tank | Plane
data Province = Province {
power :: Power,
provName :: String
} deriving (Eq)
instance Show Power where
show (Power b) = "Power " ++ show b
show (Netural) = "Netural"
show (Water) = "Water"
instance Eq Power where
(==) a b = Prelude.show a == Prelude.show b
Version1.hs
import Province
data CountrySet1 =
Country11 |
Country12
deriving (Eq, Show)
instance Country CountrySet1 where
provs =
one1:one2:[]
one1 = Province (Power Country11) "Place11"
one2 = Province (Power Country12) "Place12"
Version2.hs
import Province
data CountrySet2 =
Country21 |
Country22
deriving (Eq, Show)
instance Country CountrySet2 where
provs =
two1:two2:[]
two1 = Province (Power Country11) "Place21"
two2 = Province (Power Country12) "Place22"
答案 0 :(得分:7)
您不必在数据类型中放置类约束。您可以在a
变量上对数据类型进行参数化,以便您可以将约束放在类型类实例上,如下所示:
-- Note that I added a type variable to "Power"
data Power a = Power a | Neutral | Water
instance (Show a) => Show (Power a) where ...
instance (Eq a) => Eq (Power a) where ...
...或者你可以做大多数人做的事情并使用deriving
:
data Power a = Power a | Neutral | Water deriving (Eq, Show)
这会生成与您编写的完全相同的实例(除了Eq
一个将比您编写的更有效)。无需扩展!
然后,如果您希望a
成为特定类型,您只需这样说!
-- Version1.hs
myValue1 :: Power CountrySet1
myValue1 = ...
-- Version2.hs
myValue2 :: Power CountrySet2
myValue2 = ...
这些完全兼容,两种实现可以并存。