gpt4 book ai didi

haskell - 在没有 Monoid 实例的情况下,如何处理 Control.Lens.Indexed 中 at 的 Maybe 结果

转载 作者:行者123 更新时间:2023-12-03 20:16:53 26 4
gpt4 key购买 nike

我最近在 Hackage 上发现了镜头包,并且现在一直在尝试在一个小型测试项目中使用它,如果我继续努力的话,在很远的一天可能会变成 M​​UD/MUSH 服务器。

这是我的代码的最小化版本,说明了我现在使用用于访问键/值容器的 at 镜头面临的问题(在我的情况下为 Data.Map.Strict)

{-# 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

由于房间、玩家和类似对象在整个代码中都被引用,因此我将它们存储在我的 World 状态类型中,作为其数据对象的 Id(新类型 UUID)映射。

要检索那些有镜头的人,我需要以某种方式处理 at 镜头返回的 Maybe (如果键不在 map 中,这就是 Nothing)。在我的最后一行中,我尝试通过 traverse 执行此操作,只要最终结果是 Monoid 的实例,它就会进行类型检查,但通常情况并非如此。这不是因为 playerLocation 返回一个没有 Monoid 实例的 RoomId。
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'

由于 traverse 只需要 Monoid,因为 traverse 泛化到大小大于 1 的容器,我现在想知道是否有更好的方法来处理这个问题,它不需要我想要的对象中可能包含的所有类型的语义上无意义的 Monoid 实例存储在 map 中。

或者我可能完全误解了这里的问题,我需要使用一个完全不同的相当大的镜头包?

最佳答案

如果您有 Traversal你想得到一个Maybe对于第一个元素,您可以使用 headOf而不是 view , IE。

viewPlayerLocation :: World -> PlayerId -> Maybe RoomId
viewPlayerLocation world playerId =
headOf (worldPlayers.at playerId.traverse.playerLocation) world
headOf 的中缀版本被称为 ^? .您也可以使用 toListOf获取所有元素和其他功能的列表,具体取决于您想要做什么。见 Control.Lens.Fold 文档。

在哪个模块中查找您的函数的快速启发式方法:
  • 一个 Getter是只有一个值的只读 View
  • 一个 Lens是只有一个值的读写 View
  • 一个 Traversal是零个或多个值的读写 View
  • 一个 Fold是零个或多个值的只读 View
  • 一个 Setter是零个或多个值(实际上可能是无数个值)的只写(好吧,只修改) View
  • 一个 Iso是,嗯,一个同构——一个Lens可以往任何方向走
  • 大概您知道何时使用 Indexed函数,所以你可以查看对应的Indexed模块

  • 想一想您要做什么以及将其放入的最通用模块是什么。 :-) 在这种情况下,您有一个 Traversal ,但你只是想查看,而不是修改,所以你想要的功能在 .Fold .如果您还保证它只引用一个值,那么它将在 .Getter 中。 .

    关于haskell - 在没有 Monoid 实例的情况下,如何处理 Control.Lens.Indexed 中 at 的 Maybe 结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13434568/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com