haskell - 如何修复这种嵌套 fmap 仿函数的混乱?
问题描述
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
我已经切换到无点形式来突出三个阶段:
- 创建
ColorMap
- 创建
RoleMap
- 映射包裹在包裹里面的
coord
值。[Piese]
RoleMap
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
表达式吗?不需要。但将辅助函数与辅助函数计算的值分开可能会有所帮助。)
推荐阅读
- python-3.x - How to draw dendrogram in matplotlib without using scipy?
- list - groovy 中一键多值的示例
- hardware - 是什么让非线性函数在硬件(例如 FPGA)中的计算成本很高?
- python - 根据名称中的前几个单词移动文件
- mysql - Spring Boot War 文件未连接到 kubernetes 中的 MySQL 数据库?
- java - JPA 不会将关联对象保存在 @RequestBody 注释获取的对象中
- pytorch - 如何用pytorch将多标签分类上下文下的标签列表覆盖为one-hot编码?
- python - 如何从 Python 中的所有行和列数组中找到单个最大值并显示其行和列索引
- gradle - Gradle - Dependencies between test directories
- laravel-5.8 - SQLSTATE [23000]:违反完整性约束:1048 列“product_id”不能为空(SQL:插入“category_product”)