Question

I'm using the code below on a record that has a field '_scene' of type SceneGraph. I've created lenses for it using 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

I'm getting the error:

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

But I don't understand why SceneGraph has to be an instance of Monoid in order to use this lens.

Était-ce utile?

La solution

You probably want either (^?), or maybe (^..) (non-operator names: preview, toListOf).

When you have a Lens (or a Getter, Iso, Equality, etc.), it always refers to exactly one item. So you can use plain old (^.) (non-operator name: view). When you have have a Traversal (or a Fold, Prism, etc.), it can refer to 0-or-more items.

Therefore there must be a way to combine them if there's more than one, or a default value to give if there are none. This is done with the Monoid constraint. toListOf gives you a list of all the values; preview gives you either Nothing or Just the first value.

You didn't give the types for any of the functions you're using, so I can't really tell what you intended. My guess would be that maybe scene can fail because you used makeLenses with a sum type that doesn't define scene in every summand. In this case you'd probably want to use (^?) and handle the Nothing case. But it might be something else.

See also my answer to this question (and this question from yesterday! This seems to be a popular topic).

Autres conseils

I'm assuming you are using Ed Kmett's lens library, it would be helpful if you could also post the version you are using and the imports. It also looks like there are two versions of (^.) supported in that lens library, one with a Getter and one with a Fold, the fold version requiring an instance of Monoid: (^.) :: Monoid r => s -> Fold s r -> r

Edit: I'm betting that you accidentally imported Control.Lens.Fold

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top