I have a record type in my Haskell code to which I want to define a lens that can be used as a getter and as a setter. The code looks like this:
data Players = Players { _white :: Player
, _black :: Player
} deriving (Show, Eq)
makeLenses ''Players
_byColor :: Color -> Players -> Player
_byColor White = _white
_byColor Black = _black
byColor col = to (_byColor col)
Players
is a record holding the white and the black player. I want to be able to get a player by color in a lens fashion. E.g.
players ^. byColor White . hp -- Access health-points of player
However, I also want to be able to set a property of a player chosen by color. E.g. within a state-monad holding a Game
record with a _players
field.
let current = White
players . byColor current . hp %= (-1)
With my current definition of byColor
however the code fails to compile with the following error message:
No instance for (Contravariant Identity)
arising from a use of `byColor'
Possible fix:
add an instance declaration for (Contravariant Identity)
What am I doing wrong?
The to
combinator only makes a getter, you haven't defined a full lens. However, defining the full lens is pretty straightforward, you just need to return the correct lens based on the color passed in:
byColor :: Color -> Lens' Players Player
byColor White = white
byColor Black = black