swa*_*lay 1 haskell types interface list algebraic-data-types
所以我想为我的对象type和data对象建立某种接口。所以我有
data Tile = Tile {
coord :: Coord,
fixed :: Bool,
wiel :: Bool
} deriving (Show)
type Source = (Coord , Bool)
type Sink = (Coord , Bool)
Run Code Online (Sandbox Code Playgroud)
并想为所有这些接口创建一个全局接口,所以我希望该接口具有另一个字段,rotating :: Bool然后带有the Tile或the Source或the Sink。
如果它们在哪里都实现了相同的接口,那么它们就具有额外的字段。这样,我也可以将它们放在我也需要的列表中。(也许是一个Nothing选择,以防万一我遍历列表时没有任何东西)。
我首先尝试这样做而没有像这样的多余字段
data newInterface = Source | Sink | Tile | Nothing
Run Code Online (Sandbox Code Playgroud)
但是,这无效,因为我得到了“ Tile多次定义”错误。
我将如何解决呢?谢谢
首先,这里实际上只有两个类型定义,因为Source和Sink都是弱别名。您需要使用newtype它们来区分它们:
newtype Source = Source (Coord, Bool)
newtype Sink = Sink (Coord, Bool)
Run Code Online (Sandbox Code Playgroud)
然后,是一个存在的Typeclass反模式:
class CommonInterface where
rotating :: Bool
Run Code Online (Sandbox Code Playgroud)
以及相关的实现:
instance CommonInterface Tile where
rotating (Tile _ x _) = x
instance CommonInterface Source where
rotating (Source (_, x) = x
instance CommonInterface Sink where
rotating (Sink (_, x) = x
Run Code Online (Sandbox Code Playgroud)
现在,针对该反模式的“肉”,可以创建“异构”集合:
newtype Anything = forall a. CommonInterface a => Anything a
instance CommonInterface Anything where
rotating (Anything a) = rotating a
Run Code Online (Sandbox Code Playgroud)
当然,此时您应该阅读链接的文章,并了解为什么这种方法并非最佳方法。话虽如此,对于反模式而言,它似乎工作得很好。
当然,如果您只想拥有一种包含以上所有内容的数据类型,那就容易多了:
data Anything = AnythingSink Sink | AnythingSource Source | AnythingTile Tile | AnythingNothing
Run Code Online (Sandbox Code Playgroud)
rotating然后,必须针对所有可能的情况执行以下实现:
rotating :: Anything -> Bool
rotating (AnythingSink ...) = ...
rotating (AnythingTile ...) = ...
Run Code Online (Sandbox Code Playgroud)
这要简单得多,因为它需要事先知道所有可能性。在现有方法中,您可以添加更多类型的实现,CommonInterface而无需事先了解它们。