haskell - 为什么我的数据类型需要一个 Monoid 实例才能使用这个镜头?

标签 haskell lenses monoids haskell-lens

我在具有 SceneGraph 类型字段“_scene”的记录上使用下面的代码。我使用 makeLenses 为它创建了镜头。

inputGame :: Input -> Game -> Game
inputGame i g = flip execState g $ do
    let es = g ^. userInput . events
        sg = g ^. scene
    userInput .= i
    scene .= foldl (flip inputEvent) sg es

inputEvent :: InputEvent -> SceneGraph -> SceneGraph
inputEvent (WindowSizeChangedTo (w,h)) (SceneRoot _ _ sg) = SceneRoot w h sg
inputEvent _ sg = sg

我收到错误:
No instance for (Monoid SceneGraph) arising from a use of `scene'
Possible fix: add an instance declaration for (Monoid SceneGraph)
In the second argument of `(^.)', namely `scene'
In the expression: g ^. scene
In an equation for `sg': sg = g ^. scene

但我不明白为什么 SceneGraph 必须是 Monoid 的一个实例才能使用这个镜头。

最佳答案

您可能需要 (^?)(^..) (非运营商名称:previewtoListOf )。

当您有 Lens (或 GetterIsoEquality 等)时,它总是指代一个项目。所以你可以使用普通的旧 (^.) (非运营商名称: view )。当您有一个 Traversal (或 FoldPrism 等)时,它可以引用 0 个或多个项目。

因此,如果有多个,则必须有一种方法将它们组合起来,或者如果没有,则必须给出默认值。这是通过 Monoid 约束完成的。 toListOf 为您提供所有值的列表; preview 为您提供 NothingJust 第一个值。

您没有为您正在使用的任何功能提供类型,所以我无法真正说出您的意图。我的猜测可能是 scene 可能会失败,因为您使用 makeLenses 的 sum 类型没有在每个 summand 中定义 scene。在这种情况下,您可能希望使用 (^?) 并处理 Nothing 情况。但它可能是别的东西。

另请参阅我对 this question 的回答(以及昨天的 this question!这似乎是一个热门话题)。

关于haskell - 为什么我的数据类型需要一个 Monoid 实例才能使用这个镜头?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17538691/

相关文章:

haskell - 用于元组扩展的透镜?

haskell - 作为 Monoid 实例的函数类型

haskell - 在 Monoid 实例中需要什么 Alt?

list - Haskell类型的数学问题

parsing - 如何在 monad 转换器解析器组合器中限制回溯

scala - 为什么棱镜设置函数不返回选项/也许

haskell - 为什么 "and []"为真而 "or []"为假

haskell - 应用左星测序算子和右星测序算子预期做什么?

haskell - 什么是单态性限制?

haskell - 如何使用 Lenses 遍历并分配给 Map 中的某些(但不是全部)元素