Haskell - Lenses, use of 'to' function

Viewed 867

I have the following code. I'd like to be able to modify the active player's life when given a game state. I came up with an activePlayer lens, but when I try and use it in combination with the -= operator I receive the following error:

> over (activePlayer.life) (+1) initialState 
<interactive>:2:7:
    No instance for (Contravariant Mutator)
      arising from a use of `activePlayer'
    Possible fix:
      add an instance declaration for (Contravariant Mutator)
    In the first argument of `(.)', namely `activePlayer'
    In the first argument of `over', namely `(activePlayer . life)'
    In the expression: over (activePlayer . life) (+ 1) initialState``

and the code in question:

{-# LANGUAGE TemplateHaskell #-}
module Scratch where

import Control.Lens
import Control.Monad.Trans.Class
import Control.Monad.Trans.State
import Data.Sequence (Seq)
import qualified Data.Sequence as S

data Game = Game
    { _players :: (Int, Seq Player) -- active player, list of players
    , _winners :: Seq Player
    }
    deriving (Show)

initialState = Game
    { _players = (0, S.fromList [player1, player2])
    , _winners = S.empty
    }

data Player = Player
    { _life :: Integer
    }
    deriving (Show, Eq)

player1 = Player
    { _life = 10
    }

player2 = Player
    { _life = 10
    }

makeLenses ''Game
makeLenses ''Player

activePlayer
  :: (Functor f, Contravariant f) =>
       (Player -> f Player) -> Game -> f Game
activePlayer = players.to (\(i, ps) -> S.index ps i)

Each player takes their turn in order. I need to keep track of all the players at once as well as which is currently active, which is the reason for how I structured that, although I am open to different structures since I probably don't have the right one yet.

1 Answers
Related