Lens' is a more ranked type, and type inference is very fragile with them and basically only works when all functions that take arguments of a higher rank have explicit signatures for this. This works very poorly with contactless code using . and the like, which do not have such signatures. (Only $ has a special hack to work with it sometimes.)
The lens library itself goes around this, making sure that all functions that use the lens argument do not have a completely common lens type for it, but only a type that indicates the exact lens that they use.
In your case, this is the printHandle function, which is the culprit of this. Your code will be compiled if you change your signature to a more accurate one.
printHandle :: s -> Getting Player s Player -> IO ()
I found this signature by deleting the original one and using :t printHandle .
EDIT (and add ALens' again EDIT): if you think that “treatment is worse than the disease”, then depending on your needs there is another option that does not require you to change the signature of your function, but which requires you to do what This is an explicit conversion, use the ALens' type ALens' . Then you need to change two lines:
type PlayerLens = ALens' GameState Player ... printHandle st playerLens = do let player = st^.cloneLens playerLens ...
ALens' is a type of no higher rank that has been thought out, so that it contains all the information needed to extract a common lens from it using cloneLens . But it is still a special subtype of the lens (only Functor was specifically selected), so you only need an explicit conversion from ALens' to Lens' , and not vice versa.
The third option, which may not be the best for lenses, but which usually works for higher rank types in general, is to turn your PlayerLens into a newtype :
newtype PlayerLens = PL (Lens' GameState Player)
Of course, now this requires both packaging and deployment in several places of your code. getPlayerLens was especially broken:
getPlayerLens :: PlayerHandle -> PlayerLens getPlayerLens handle = PL playerLens where playerLens f st = fmap put' get' where players = st^.gamePlayers put' player = let gp = case p^.playerHandle == handle of True -> player False -> p in set gamePlayers (map g players) st get' = f $ fromJust $ find (\p -> p^.playerHandle == handle) players