Search code examples
haskellhaskell-lenslenses

Modifying the target of a Lens conditionally


I have a function that produces an updated board from an input and a board, if the move is permitted by the rules of the game:

move :: Input -> Board -> Maybe Board

The board is wrapped in the GameState type with some additional data:

type GameState = (Board, ...)

Now I'd like to use lenses to update the board in the game state if move yields Just a value. I can do this with a helper function:

updateGameState :: Input -> GameState -> GameState
updateGameState input gs = gs & _1 %~ (f $ move input)
  where
    f g x = maybe x id (g x)

However, I'm wondering if there is a combinator that modifies the target of a Lens only if the supplied function returns a Just. I've found the ?~ operator, but that handles partiality on the left hand side.

Is there a (likely more general) combinator that can achieve this, or is there another way to express this in a terse and idiomatic way?


Solution

  • You could do

    import Control.Applicative
    import Data.Maybe
    
    updateGameState :: Input -> GameState -> GameState
    updateGameState input = fromMaybe <*> _1 (move input)
    -- updateGameState x s = fromMaybe s $ _1 $ move x
    

    This uses the fact that Lens s t a b is a type alias for forall f . Functor f => (a -> f b) -> (s -> f t), so we can choose to use Maybe as f and get a function of type GameState -> Maybe GameState.