In der Funktion test
traversiere ich über eine Liste, erzeuge Linsen von ihren Mitgliedern und drucke dann einige Daten aus. Das funktioniert, wenn ich einen sinnvollen Anrufstil verwende. Es schlägt fehl, wenn ich es point-free mache.Punktfreie Objektiverstellung wird nicht geprüft
Warum ist das der Fall, und wie kann ich dieses Problem lösen?
Es sieht aus wie ich, dass GHC nicht die Information, dass die höherrangige f
(im Objektiv) ist ein Functor
bei der Verwendung von Punkt-freien Stil, aber ich bin mir nicht sicher.
Ich verwende GHC 7.8.3
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
import Control.Monad
import Data.List
import Data.Maybe
type PlayerHandle = String
data Player = Player { _playerHandle :: PlayerHandle }
makeLenses ''Player
data GameState = GameState { _gamePlayers :: [Player] }
makeLenses ''GameState
type PlayerLens = Lens' GameState Player
getPlayerLens :: PlayerHandle -> PlayerLens
getPlayerLens handle f st = fmap put' get'
where
players = st^.gamePlayers
put' player = let
g p = 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
printHandle :: GameState -> PlayerLens -> IO()
printHandle st playerLens = do
let player = st^.playerLens
print $ player^.playerHandle
test :: GameState -> IO()
test st = do
let handles = toListOf (gamePlayers.traversed.playerHandle) st
--
-- Works: Pointful
--forM_ handles $ \handle -> printHandle st $ getPlayerLens handle
--
-- Does not work: Point-free
forM_ handles $ printHandle st . getPlayerLens
main :: IO()
main = test $ GameState [Player "Bob", Player "Joe"]
Test.hs:45:38:
Couldn't match type `(Player -> f0 Player)
-> GameState -> f0 GameState'
with `forall (f :: * -> *).
Functor f =>
(Player -> f Player) -> GameState -> f GameState'
Expected type: PlayerHandle -> PlayerLens
Actual type: PlayerHandle
-> (Player -> f0 Player) -> GameState -> f0 GameState
In the second argument of `(.)', namely `getPlayerLens'
In the second argument of `($)', namely
`printHandle st . getPlayerLens'
Failed, modules loaded: none.
Ich weiß nicht, die Details, aber ich bin mir ziemlich sicher, dass es etwas mit höherrangigen Arten verursacht einige Typisierung Problemen zu tun. Das Übergeben von Lens-Argumenten kann diese Art von Problem verursachen. Es wird wahrscheinlich funktionieren, wenn Sie 'ALens' anstelle von' Lens' verwenden, da dies so ausgelegt ist, dass es herumgereicht wird. –
@DavidYoung Sie können * es mit 'ALens' machen, aber dann muss die aufgerufene Funktion es explizit zu einem normalen Objektiv" klonen ", bevor es es benutzt. Das ist normalerweise nur für eine Funktion geeignet, die wirklich die vollen Objektiveigenschaften ihres Arguments benötigt. –
@DavidYoung: Ich werde es untersuchen müssen. Ein schneller Google hat keine Tutorials/Beispiele für "ALens" über "Lens" ergeben, aber ich sollte es herausfinden können. Es ist Zeit, den Tag für jetzt zu beenden. –