2013-12-11 6 views
9

Ich habe den folgenden Code. Ich würde gerne in der Lage sein, das Leben des aktiven Spielers zu verändern, wenn ihm ein Spielstatus zugewiesen wird. Ich kam mit einem activePlayer Objektiv, aber wenn ich versuche, und verwenden Sie es in Kombination mit dem -= Operator ich die folgende Fehlermeldung:Haskell - Linsen, Verwendung von 'zu' Funktion

> over (activePlayer.life) (+1) initialState 
<interactive>:2:7: 
    No instance for (Contravariant Mutator) 
     arising from a use of `activePlayer' 
    Possible fix: 
     add an instance declaration for (Contravariant Mutator) 
    In the first argument of `(.)', namely `activePlayer' 
    In the first argument of `over', namely `(activePlayer . life)' 
    In the expression: over (activePlayer . life) (+ 1) initialState`` 

und den Code in Frage:

{-# LANGUAGE TemplateHaskell #-} 
module Scratch where 

import Control.Lens 
import Control.Monad.Trans.Class 
import Control.Monad.Trans.State 
import Data.Sequence (Seq) 
import qualified Data.Sequence as S 

data Game = Game 
    { _players :: (Int, Seq Player) -- active player, list of players 
    , _winners :: Seq Player 
    } 
    deriving (Show) 

initialState = Game 
    { _players = (0, S.fromList [player1, player2]) 
    , _winners = S.empty 
    } 

data Player = Player 
    { _life :: Integer 
    } 
    deriving (Show, Eq) 

player1 = Player 
    { _life = 10 
    } 

player2 = Player 
    { _life = 10 
    } 

makeLenses ''Game 
makeLenses ''Player 

activePlayer 
    :: (Functor f, Contravariant f) => 
     (Player -> f Player) -> Game -> f Game 
activePlayer = players.to (\(i, ps) -> S.index ps i) 

Jeder Spieler nimmt sie sind an der Reihe. Ich muss den Überblick über alle Spieler auf einmal behalten und auch, was gerade aktiv ist. Aus diesem Grund habe ich das strukturiert, obwohl ich offen für verschiedene Strukturen bin, da ich wahrscheinlich noch nicht die richtige habe.

+2

Ich denke, dein Problem ist, dass die Definition von 'activePlayer 'es erlaubt, als Getter zu fungieren, aber nicht als Setter - du hast ihm gesagt, wie man einen Spieler aus der Sequence zieht, aber nicht wie man das ändert aktiver Spieler - daher kann er nicht zum Ändern von Spielern verwendet werden. Schau dir die Art von 'to' ---'> an: i to' ergibt 'to :: (a -> c) -> Getter a b c d' –

Antwort

12

Wenn Sie verschiedene Objekte in der Objektivbibliothek mit (.) zusammensetzen, können sie je nach Art der Subtypisierung (siehe unten) ihre Fähigkeiten verlieren. In diesem Fall haben Sie eine Lens (players) mit einem Getter (to f für eine Funktion f) und damit die Kombination ist nur ein Getter während over wirkt auf Linsen zusammengesetzt, die beide bekommen und einstellen.

activePlayer sollte jedoch ein gültiges Objektiv bilden, so dass Sie es einfach manuell als Getter/Setter-Paar schreiben können. Ich schreibe es teilweise unten unter der Annahme, dass der Index niemals ungültig sein kann.

activePlayer :: Lens' Game Player 
activePlayer = lens get set 
    where 
    get :: Game -> Player 
    get (Game { _players = (index, seq) }) = Seq.index seq index 

    set :: Game -> Player -> Game 
    set [email protected](Game { _players = (index, seq) }) player = 
     g { _players = (index, Seq.update index player seq) } 

Zum besseren Verständnis der Subtypisierung zu verstehen, die in der lens Bibliothek auftreten sind können wir the Big Lattice Diagram from Hackage

the Big Lattice Diagram from Hackage

Jedes Mal, wenn Sie Typen mit (.) Sie mit ihrem ersten gemeinsamen Nachkommen in diesem Diagramm am Ende kombinieren zwei Objektive verwenden, . Also, wenn Sie Lens und Prism kombinieren, können Sie sehen, dass ihre Pfeile auf Traversal konvergieren. Wenn Sie Lens und Getter (davon to f) kombinieren, erhalten Sie eine Getter, da Getter ein direkter Nachkomme von Lens ist.

+0

Danke, das Diagramm macht jetzt Sinn. War vorher beängstigend. Ein möglicher Tippfehler, ich denke deine Art von Set sollte "Spiel -> Spieler -> Spiel" korrekt sein? Zumindest hat 'Spieler -> Spiel -> Spieler 'keine Kontrolle gegeben, als ich es versuchte. – Dwilson

+0

Dieses Diagramm ist irgendwie gruselig, bis Sie es brauchen - und yup, Typo genau. Das ist es, was ich bekomme, weil ich meinen eigenen Code nicht wirklich überprüft habe. :) –

Verwandte Themen