data Color = White | Black deriving (Eq, Show)
data Role = King | Queen | Rook deriving (Eq, Show)
data Piece = Piece { color :: Color,
role :: Role } deriving (Eq)
data Piese = Piese { piece :: Piece,
coord :: Coord } deriving (Eq)
data ColorMap a = ColorMap {
white :: a,
black :: a
} deriving (Eq)
instance Functor ColorMap where
fmap fn (ColorMap white black) =
ColorMap (fn white) (fn black)
colorMapFromList :: (a -> Color) -> [a] -> ColorMap [a]
colorMapFromList fn lst = ColorMap
(filter ((== White) . fn) lst)
(filter ((== Black) . fn) lst)
data RoleMap a = RoleMap {
king :: a,
queen :: a,
rook :: a }
instance Functor RoleMap where
fmap fn (RoleMap king queen rook) =
RoleMap (fn king) (fn queen) (fn rook)
roleMapFromList :: (a -> Role) -> [a] -> RoleMap [a]
roleMapFromList fn lst = RoleMap
(filter ((== King ) . fn) lst)
(filter ((== Queen) . fn) lst)
(filter ((== Rook ) . fn) lst)
mapso :: [Piese] -> ColorMap (RoleMap [Coord])
mapso lst =
fmap (fmap (fmap coord)) -- ColorMap (RoleMap [Coord])
(fmap (roleMapFromList (role . piece)) -- ColorMap (RoleMap [Piese])
(colorMapFromList (color . piece) -- ColorMap [Piese]
lst)) -- [Piese]
我刚刚跳入 Haskell,它可以编译,但对我来说似乎很容易出错。这里有我可以简化的模式吗?特别是 mapso
函数。
最佳答案
您可以利用仿函数组合这一事实。虽然您可以通过使用 Data.Functor.Compose
定义新类型来相当明确地表示这一点,但实际上,这仅意味着您可以将 fmap
与自身组合。
mapso :: [Piese] -> ColorMap (RoleMap [Coord])
mapso lst = fmap (fmap (fmap coord))
(fmap (roleMapFromList (role.piece)) (colorMapFromList (color.piece) lst))
变成了
mapso = (fmap . fmap . fmap) coord .
fmap (roleMapFromList (role.piece)) .
colorMapFromList (color.piece)
或者进行一些重构:
mapso = let fffmap = fmap . fmap . fmap
makeColorMap = colorMapFromList (color.piece)
makeRoleMap = roleMapFromList (role.piece)
in fffmap coord .
fmap makeRoleMap .
makeColorMap
我已切换到无点形式来突出显示三个阶段:
- 创建
颜色映射
- 创建
角色映射
- 将
coord
映射到包装在RoleMap
内的[Piese]
值,包装在ColorMap
内。<
我们使用函数组合来减少 mapso
定义中显式嵌套的数量。
如果您还不习惯思考函数组合,您可以在 let
表达式中定义更多临时变量:
mapso lst = let fffmap = fmap . fmap . fmap
makeColorMap = colorMapFromList (color.piece)
makeRoleMap = fmap (roleMapFromList (role.piece))
in let colorMap = makeColorMap lst
rolemap = makeRoleMap colorMap
in fffmap coord roleMap
(我们需要两个 let
表达式吗?不需要。但是将辅助函数与辅助函数计算的值分开可能会有所帮助。)
关于haskell - 如何修复这种嵌套 fmap 仿函数的困惑?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69092450/