Gần đây tôi đã phát hiện gói ống kính trên Hackage và đã cố gắng tận dụng nó trong một dự án thử nghiệm nhỏ có thể biến thành MUD/MUSH máy chủ một ngày rất xa nếu tôi tiếp tục làm việc trên nó.Làm cách nào để xử lý kết quả Có thể có tại trong Control.Lens.Indexed mà không có một ví dụ Monoid
Đây là một phiên bản thu nhỏ của mã của tôi minh họa cho các vấn đề tôi phải đối mặt ngay bây giờ với ít ống kính sử dụng để truy cập vào container Key/Value (Data.Map.Strict trong trường hợp của tôi)
{-# LANGUAGE OverloadedStrings, GeneralizedNewtypeDeriving, TemplateHaskell #-}
module World where
import Control.Applicative ((<$>),(<*>), pure)
import Control.Lens
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as DM
import Data.Maybe
import Data.UUID
import Data.Text (Text)
import qualified Data.Text as T
import System.Random (Random, randomIO)
newtype RoomId = RoomId UUID deriving (Eq, Ord, Show, Read, Random)
newtype PlayerId = PlayerId UUID deriving (Eq, Ord, Show, Read, Random)
data Room =
Room { _roomId :: RoomId
, _roomName :: Text
, _roomDescription :: Text
, _roomPlayers :: [PlayerId]
} deriving (Eq, Ord, Show, Read)
makeLenses ''Room
data Player =
Player { _playerId :: PlayerId
, _playerDisplayName :: Text
, _playerLocation :: RoomId
} deriving (Eq, Ord, Show, Read)
makeLenses ''Player
data World =
World { _worldRooms :: Map RoomId Room
, _worldPlayers :: Map PlayerId Player
} deriving (Eq, Ord, Show, Read)
makeLenses ''World
mkWorld :: IO World
mkWorld = do
r1 <- Room <$> randomIO <*> (pure "The Singularity") <*> (pure "You are standing in the only place in the whole world") <*> (pure [])
p1 <- Player <$> randomIO <*> (pure "testplayer1") <*> (pure $ r1^.roomId)
let rooms = at (r1^.roomId) ?~ (set roomPlayers [p1^.playerId] r1) $ DM.empty
players = at (p1^.playerId) ?~ p1 $ DM.empty in do
return $ World rooms players
viewPlayerLocation :: World -> PlayerId -> RoomId
viewPlayerLocation world playerId=
view (worldPlayers.at playerId.traverse.playerLocation) world
Từ phòng , người chơi và các đối tượng tương tự được tham chiếu trên tất cả các mã tôi lưu trữ chúng trong loại trạng thái thế giới của tôi như là bản đồ của các Id (newtyped UUID) cho các đối tượng dữ liệu của chúng.
Để tìm những người có ống kính, tôi cần xử lý Có thể được trả về bởi ống kính tại (trong trường hợp khóa không có trong bản đồ thì không có gì) bằng cách nào đó. Trong dòng cuối cùng của tôi, tôi đã cố gắng để làm điều này thông qua đi qua mà không typecheck miễn là kết quả cuối cùng là một ví dụ của Monoid nhưng điều này không phải là trường hợp chung. Ngay tại đây không phải vì playerLocation trả về một RoomId mà không có Monoid instance.
No instance for (Data.Monoid.Monoid RoomId)
arising from a use of `traverse'
Possible fix:
add an instance declaration for (Data.Monoid.Monoid RoomId)
In the first argument of `(.)', namely `traverse'
In the second argument of `(.)', namely `traverse . playerLocation'
In the second argument of `(.)', namely
`at playerId . traverse . playerLocation'
Kể từ khi monoid là yêu cầu của traverse chỉ vì traverse khái quát để đựng các kích cỡ lớn hơn một bây giờ tôi đã tự hỏi nếu có một cách tốt hơn để xử lý này mà không đòi hỏi các trường hợp monoid ngữ nghĩa vô nghĩa trên tất cả các loại có thể chứa trong một đối tượng của tôi mà tôi muốn lưu trữ trên bản đồ.
Hoặc có thể tôi đã hiểu sai vấn đề ở đây hoàn toàn và tôi cần sử dụng một bit hoàn toàn khác so với gói thấu kính khá lớn?
Điều gì về việc sử dụng các đơn nguyên 'First' hoặc' Last' từ 'Data.Monoid'? –