【发布时间】:2019-02-22 21:22:05
【问题描述】:
我正在尝试制作井字游戏,我决定为单元格(棋盘的元素)和棋盘构造类型如下:
data Cell = X | O deriving (Show, Eq)
type Board = [[Maybe Cell]]
这里,Nothing 表示一个空单元格,(Just X) 和 (Just O) 分别表示用 X 和 O 填充的单元格。
我想将 (Maybe Cell) 定义为一个幺半群,如下所示:
instance Monoid (Maybe Cell) where
mempty = Nothing
mappend Nothing x = x
mappend (Just x) _ = (Just x)
Board 作为另一个幺半群
instance Monoid Board where
mempty = [[Nothing, Nothing, Nothing]
,[Nothing, Nothing, Nothing]
,[Nothing, Nothing, Nothing]]
mappend = zipWith (zipWith mappend)
-- where the right-hand-side mappend is the addition on (Maybe Cell)
我知道我完全可以在没有幺半群的情况下实现这一点,但我正在尝试探索这个领域,它只是一种非常巧妙的编写方式。
我得到的问题是 Maybe 的 monoid 实例已经在 GHC.Base 中定义如下:
instance Semigroup a => Monoid (Maybe a)
这与我想要的定义非常不同,但它会导致重复的实例声明,所以我不能忽略它。
我要做的是从GHC.Base 中隐藏(Maybe a) 的Monoid 实例以避免重复实例。我尝试了很多搜索,但无法真正找到隐藏它的方法。我无法隐藏所有Monoid 或所有Semigroup,因为我需要它们的功能,但我需要隐藏这个特定的实例声明。谁能帮我解决这个问题?
注意:我使用的是 FlexibleInstances。
【问题讨论】:
-
您无法隐藏
instance声明。您可以做的是使用newtype来“包装”基础类型。这甚至在标准库中也做了很多 - 例如Sum和Product类型都是Int的包装器(实际上是Num的任何实例),具有不同的Monoid实例。 -
哦,您的
Monoid实例Maybe Cell已经作为newtype包装器存在:hackage.haskell.org/package/base-4.12.0.0/docs/… -
@RobinZigmond 哇!那太快了!它是正确的;
First完全解决了这个问题。非常感谢!
标签: haskell typeclass monoids semigroup