Reputation: 54058
In yet another attempt to teach myself ekmett's lens library, I'm modifying a simple text-based hangman game to use lenses instead of record updates. The code itself works, but I've come across a place where I feel like I'm using the lens library incorrectly. This code works correctly, but it just doesn't look as elegant to me as all the lens tutorials I've seen.
First, my types:
data GameState = GameState
{ _guess :: Set Char
, _secret :: String
, _wrongGuesses :: Int
} deriving (Eq, Show)
makeLenses ''GameState
type Game a = StateT GameState IO a
The function I'm bothered by is where I process the guess obtained from the user:
nextGuess :: Game ()
nextGuess = do
gs <- get -- GameState
g <- getUserGuess :: Game Char
-- If the user guessed a letter that wasn't in the secret word
when (g `notElem` gs^.secret) $
-- increment the number of wrong guesses
wrongGuesses += 1
-- Insert that guess into the set of guesses
guess .= gs^.guess.to (insert g)
I'm mostly fine with the line
when (g `notElem` gs^.secret) $ wrongGuesses += 1
But the next line, where the guess is inserted into the current set of guesses seems like a roundabout way to do it. Having to get the current set, insert, then set it again just doesn't sound like the "lens way of doing things", especially when the line before all I have to do to increment the wrongGuesses
counter is use += 1
.
Is there a better way to do this?
Upvotes: 2
Views: 276
Reputation: 53871
Unless I'm much mistaken,
guess %= insert g
(%=)
acts as modify and will feed the Set
into insert g
and then stick it back into guess
.
Upvotes: 4