Difficulty with increase and free monads

I cheat with free monads and a lens, using the free monad to create my own version of the IO monad:

data MyIO next = LogMsg String next | GetInput (String -> next) deriving (Functor) 

I put this on top of the state monad like this: FreeT MyIO (State GameState) a where GameState :

 data GameState = GameState { _players :: [PlayerState] } 

Now, what I would like is a way to "zoom in" a PlayerState from the context of a GameState . Something like that:

 zoomPlayer :: Int -> FreeT MyIO (State PlayerState) a -> FreeT MyIO (State GameState) a zoomPlayer i prog = hoistFreeT (zoom (players . element i)) prog 

But I get this error:

 No instance for (Data.Monoid.Monoid a1) arising from a use of '_head' 

This error seems to be related to what players . element i players . element i - bypass; if I _players list aspect from _players and use a regular lens, then the code works.

Any ideas on how to write this feature?

+5
source share
1 answer

If you are sure that you will never be indexed into a nonexistent player and are not against a little insecurity, you can use unsafeSingular to turn a Traversal into Lens , for example:

 zoomPlayer :: Int -> FreeT MyIO (State PlayerState) a -> FreeT MyIO (State GameState) a zoomPlayer i prog = hoistFreeT (zoom (players . unsafeSingular (element i))) prog 

(Perhaps I used ix instead of element , but not related to the problem.)

We can also create reliable indexing lenses for infinitely infinite sequences, such as streams defined using Cofree from the free package:

 import Control.Lens (Lens', _Wrapped') import Control.Comonad.Cofree (Cofree, telescoped) import Data.Functor.Identity import Control sureIx :: Int -> Lens' (Cofree Identity a) a sureIx i = telescoped $ replicate i _Wrapped' 

But the game is unlikely to have endless players.

+2
source

All Articles