data Color = White | Black deriving (Eq, Show)。
data Role = King | Queen | Rook deriving (Eq, Show)。
data Piece = Piece { color :: Color,
角色 :: Role } deriving (Eq)
data Piese = Piese { piece : : Piece,
coord :: Coord } deriving (Eq)。
data ColorMap a = ColorMap {
white :: a,
黑 :: aderiving (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 [a
(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 [a
(filter ((== King ) . fn) lst)
(filter ((== Queen ) . fn) lst)
(filter ((== Rook ). fn) lst)
mapso :: [Piese] -> ColorMap (RoleMap [Coord] )
mapso lst =
fmap (fmap (fmap coordord)) -- ColorMap (RoleMap [Coord])
(fmap (roleMapFromList (role . piece)) -- ColorMap (RoleMap [Piese])
(colorMapFromList (color . piece) -- ColorMap [Piese])
lst)) -- [Piese]
我剛開始接觸Haskell,這個可以編譯,但我覺得它似乎很容易出錯。這里是否有一個模式,我可以把它簡化成?特別是mapso函式。
uj5u.com熱心網友回復:
你可以利用漏斗組成的事實。雖然你可以通過用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映射到包裹在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 coordinate roleMap
(我們需要兩個let運算式嗎?不需要。但是把輔助函式和輔助函式計算的值分開可能會有幫助。
uj5u.com熱心網友回復:
一種選擇是讓你的地圖成為Monoid實體。所以:
instance Semigroup a => Semigroup (RoleMap a) where
RoleMap ks qs rs <> RoleMap ks' qs' rs' =
RoleMap (ks <> ks') (qs <> qs') (rs <> rs')
instance Monoid a => Monoid (RoleMap a) where
mempty = RoleMap mempty mempty mempty
instance Semigroup a => Semigroup (ColorMap a) where
ColorMap ws bs <> ColorMap ws' bs' =
ColorMap (ws <> ws') (bs <> bs')
instance Monoid a => Monoid (ColorMap a) where
mempty = ColorMap mempty mempty
現在,代替過濾,提供一個函式來創建單子地圖。
singletonRole :: Monoid a => Role -> a -> RoleMap a
singletonRole r a = case r of >。
King -> mempty { king = a }
Queen -> mempty { queen = a }
Rook -> mempty { rook = a }
singletonColor :: Monoid a => Color -> a -> ColorMap a
singletonColor c a = case cof
White -> mempty { white = a }
Black -> mempty { black = a }
使用這些,很容易寫出一個消耗單個Piese的函式:
singletonFromPiese :: Piese -> ColorMap (RoleMap [Coord] )
singletonFromPiese (Piese p c) =
singletonColor (color p) .
singletonRole (role p) $ [c] 。
消耗大量的Pieses只是一個foldMap:
mapso :: [Piese] -> ColorMap (RoleMap [Coord])
mapso = foldMap singletonFromPiese
這種方法的一個好處是,對我來說,每一段單獨的代碼看起來都很明顯,不需要進行心理型別推理。嵌套的 fmap -- 即使我們將它們視為一個組成型別上的單個 fmap -- 也不具備這種屬性,至少對我來說是這樣。
另一個很好的屬性是我們只對串列進行一次傳遞;在fmap版本的明顯實作中,我們對創建RoleMap的三個過濾器進行三次傳遞,對創建ColorMap的兩個過濾器進行兩次傳遞,總共有五個傳遞。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/316921.html
標籤:
