В функции test
я просматриваю список, генерирую линзы из его членов, а затем печатаю некоторые данные. Это работает, когда я использую точечный стиль вызова. Он не проверяет тип, когда я делаю его безточечным.
Почему это так, и как я могу решить эту проблему?
Мне кажется, что GHC не сохраняет информацию о том, что f
с более высоким рейтингом (в объективе) является Functor
при использовании бесточечного стиля, но я не слишком уверен.
Я использую 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.
Lens
может вызвать такую проблему. Вероятно, это сработает, если вы используетеALens
вместоLens
, так как это предназначено для передачи. - person David Young   schedule 23.03.2015ALens
, но тогда вызываемая функция должна явноcloneLens
вернуться к обычному объективу, прежде чем использовать его. Обычно это подходит только для функции, которой действительно нужны полные функции линзы ее аргумента. - person Ørjan Johansen   schedule 23.03.2015ALens
надLens
, но я должен понять это. Время, чтобы назвать день уходит на данный момент. - person Thomas Eding   schedule 23.03.2015ALens
лучше подходит для линз, чем мой альтернативныйnewtype
хак, если кто-то настаивает на постоянном типе, поэтому теперь я также включил их в свой ответ. (Я думаю, что использование определенных типов на сайтах использования еще более идиоматично.) - person Ørjan Johansen   schedule 23.03.2015