6

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?

vtan
  • 75
  • 4

1 Answers1

6

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.

felix-eku
  • 2,203
  • 17
  • 20
  • Thanks. The `Applicative` instance of `(->) r` and this `fromMaybe <*> f` idiom is what I've been looking for. – vtan Jan 20 '15 at 18:15