在 Haskell 中导入时隐藏类型类实例声明
Hiding typeclass instance declarations while importing in Haskell
我正在尝试制作一个井字游戏,我决定按如下方式为单元格(棋盘元素)和棋盘构建类型:
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。
I standard Haskell, class 实例总是“完全全局”† – 如果一个类型有一个给定的实例 class 某处,则此实例无处不在
所以,如果你想定义一个单独的实例,你需要有一个不同的 class - 通常不实用,包括在你的例子中 - 或者不同的类型,这通常不是问题。事实上Haskell有一个专门针对这种东西的关键字,newtype
。您只需将 type Board = [[Maybe Cell]]
更改为
newtype Board = Board [[Maybe Cell]]
然后
instance Semigroup Board where
Board l <> Board r = Board $ zipWith (zipWith mappend) l r
instance Monoid Board where
mempty = Board [[Nothing, Nothing, Nothing]
,[Nothing, Nothing, Nothing]
,[Nothing, Nothing, Nothing]]
mappend = (<>)
同样,您应该使用具有合适 Monoid
实例的另一种类型,而不是 Maybe Cell
。那个实际上 exists already in the base library,但它并不是真正必要的:你可以为 Cell
本身创建一个半群(不是幺半群!)实例,它代表左偏,然后 Maybe
将(因为GHC-8.4) 自动具有所需的行为。
instance Semigroup Cell where
a <> _ = a
†其实已经有人提出放宽这个,允许本地选择实例,在a paper presented at the 2018 Haskell Symposium.
我正在尝试制作一个井字游戏,我决定按如下方式为单元格(棋盘元素)和棋盘构建类型:
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。
I standard Haskell, class 实例总是“完全全局”† – 如果一个类型有一个给定的实例 class 某处,则此实例无处不在
所以,如果你想定义一个单独的实例,你需要有一个不同的 class - 通常不实用,包括在你的例子中 - 或者不同的类型,这通常不是问题。事实上Haskell有一个专门针对这种东西的关键字,newtype
。您只需将 type Board = [[Maybe Cell]]
更改为
newtype Board = Board [[Maybe Cell]]
然后
instance Semigroup Board where
Board l <> Board r = Board $ zipWith (zipWith mappend) l r
instance Monoid Board where
mempty = Board [[Nothing, Nothing, Nothing]
,[Nothing, Nothing, Nothing]
,[Nothing, Nothing, Nothing]]
mappend = (<>)
同样,您应该使用具有合适 Monoid
实例的另一种类型,而不是 Maybe Cell
。那个实际上 exists already in the base library,但它并不是真正必要的:你可以为 Cell
本身创建一个半群(不是幺半群!)实例,它代表左偏,然后 Maybe
将(因为GHC-8.4) 自动具有所需的行为。
instance Semigroup Cell where
a <> _ = a
†其实已经有人提出放宽这个,允许本地选择实例,在a paper presented at the 2018 Haskell Symposium.