我在具有 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 的一个实例才能使用这个镜头。
最佳答案
您可能需要 (^?)
或 (^..)
(非运营商名称:preview
、 toListOf
)。
当您有 Lens
(或 Getter
、 Iso
、 Equality
等)时,它总是指代一个项目。所以你可以使用普通的旧 (^.)
(非运营商名称: view
)。当您有一个 Traversal
(或 Fold
、 Prism
等)时,它可以引用 0 个或多个项目。
因此,如果有多个,则必须有一种方法将它们组合起来,或者如果没有,则必须给出默认值。这是通过 Monoid
约束完成的。 toListOf
为您提供所有值的列表; preview
为您提供 Nothing
或 Just
第一个值。
您没有为您正在使用的任何功能提供类型,所以我无法真正说出您的意图。我的猜测可能是 scene
可能会失败,因为您使用 makeLenses
的 sum 类型没有在每个 summand 中定义 scene
。在这种情况下,您可能希望使用 (^?)
并处理 Nothing
情况。但它可能是别的东西。
另请参阅我对 this question 的回答(以及昨天的 this question!这似乎是一个热门话题)。
关于haskell - 为什么我的数据类型需要一个 Monoid 实例才能使用这个镜头?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17538691/