2013-12-11 9 views
9

मेरे पास निम्न कोड है। जब मैं गेम स्टेटस देता हूं तो मैं सक्रिय खिलाड़ी के जीवन को संशोधित करने में सक्षम होना चाहता हूं। मैं एक activePlayer लेंस के साथ आया था, लेकिन जब मैं कोशिश करते हैं और -= ऑपरेटर मैं निम्न त्रुटि प्राप्त के साथ संयोजन में इसका इस्तेमाल करते हैं:हास्केल - लेंस, 'टू' फ़ंक्शन का उपयोग

> 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`` 

और प्रश्न में कोड:

{-# 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) 

प्रत्येक खिलाड़ी ले जाता है क्रम में उनकी बारी। मुझे एक ही समय में सभी खिलाड़ियों का ट्रैक रखने की आवश्यकता है, साथ ही वर्तमान में सक्रिय है, यही कारण है कि मैंने इसे कैसे संरचित किया, हालांकि मैं अलग-अलग संरचनाओं के लिए खुला हूं क्योंकि मेरे पास अभी तक सही नहीं है।

+2

मुझे लगता है कि आपकी समस्या यह है कि 'सक्रियप्लेयर' की परिभाषा इसे गेटर के रूप में कार्य करने की अनुमति देती है, लेकिन एक सेटटर के रूप में नहीं - आपने यह बताया है कि अनुक्रम के बाहर किसी खिलाड़ी को कैसे खींचें, लेकिन कैसे नहीं बदला जाए सक्रिय खिलाड़ी - इसलिए इसका उपयोग खिलाड़ियों को संशोधित करने के लिए नहीं किया जा सकता है। 'To' के प्रकार की जांच करें-'>: i to 'में परिणाम' to :: (a -> c) -> गेटटर ए बी सी डी –

उत्तर

12

जब आप (.) के साथ लेंस लाइब्रेरी में विभिन्न आइटम लिखते हैं तो वे एक प्रकार के उप प्रकार (नीचे देखें) के अनुसार क्षमताओं को खो सकते हैं। इस मामले में, आप बना दिया है एक Lens (players) एक Getter (to f कुछ समारोह f के लिए) और इस तरह संयोजन के साथ सिर्फ एक Getter जबकि over लेंस है कि दोनों हो और निर्धारित कर सकते हैं पर कार्य करता है।

activePlayer वैध लेंस बनाना चाहिए, हालांकि, आप इसे गेटर/सेटर जोड़ी के रूप में मैन्युअल रूप से लिख सकते हैं। मैं इस धारणा के तहत आंशिक रूप से नीचे लिख रहा हूं कि सूचकांक कभी भी अमान्य नहीं हो सकता है।

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) } 

बेहतर subtyping कि lens पुस्तकालय में होने वाली है समझने के लिए हम उपयोग कर सकते हैं the Big Lattice Diagram from Hackage

the Big Lattice Diagram from Hackage

जब भी आप (.) आपको लगता है कि चार्ट में अपना पहला आम वंशज के साथ अंत के साथ दो लेंस प्रकार गठबंधन । तो यदि आप Lens और Prism गठबंधन करते हैं तो आप देख सकते हैं कि उनके तीर Traversal पर एकत्रित होते हैं। यदि आप Lens और Getter (to f है) को गठबंधन करते हैं तो आपको Getter मिलते हैं क्योंकि GetterLens का प्रत्यक्ष वंशज है।

+0

धन्यवाद, यह चित्र वास्तव में अब समझ में आता है। पहले डरावना था। एक संभावित टाइपो, मुझे लगता है कि आपका प्रकार का सेट 'गेम -> प्लेयर -> गेम' सही होना चाहिए? कम से कम, 'प्लेयर -> गेम -> प्लेयर' ने कोशिश की जब मैंने कोशिश की। – Dwilson

+0

वह चित्र तब तक डरावना है जब तक आपको इसकी आवश्यकता न हो - और yup, टाइपो ठीक है। वास्तव में मेरे कोड को टाइप-चेक करने के लिए मुझे यही मिलता है। :) –

संबंधित मुद्दे