2013-12-11 17 views
9

私は次のコードを持っています。私は、ゲームの状態が与えられたときにアクティブなプレイヤーの人生を変更することができるようにしたいと思います。私はactivePlayerレンズを思い付いたが、私がしようとすると-=演算子と組み合わせて使用​​するときに、私は次のエラーが表示されますハスケル - レンズ、 'to'関数の使用

> 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 :(a - > c) - > Getter a b c d'の結果を確認してください。 –

答えて

12

彼らは(下記参照)サブタイプの種類に応じて機能を失う可能性があります。この場合、Getter(一部の機能ではto f)のLensplayers)を作成しました。この組み合わせは、Getterです。overは、取得と設定が可能なレンズで動作します。

activePlayer

は、しかし、有効なレンズを形成しなければならないので、あなただけのgetter/setterメソッドペアとして手動でそれを書くことができます。私はインデックスを無効にすることはできないという前提のもと、部分的に下に書いています。

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

良くlensライブラリで発生だサブタイプを理解するために、我々は使用することができ、あなたがそのチャートに初の共通子孫で終わる(.)で2種類のレンズを組み合わせたときはいつでもthe Big Lattice Diagram from Hackage

the Big Lattice Diagram from Hackage

。したがって、LensPrismを組み合わせると、矢印がTraversalに収束していることがわかります。 LensGetter(そのうちto f)を組み合わせた場合、GetterLensの直系であるため、Getterとなります。変更するにはどのようにシーケンス外のプレーヤーを引くためにどのようにそれを言ったではなく - 私はあなたの問題がactivePlayer` `の定義は、それがゲッターとしてではなく、セッターとして機能することを可能にするということだと思います

+0

ありがとうございました。以前は怖かったです。 1つのタイプミスは、あなたのタイプは 'Game - > Player - > Game'であるべきだと思いますか?少なくとも、Player - > Game - > Player'は試したときにタイプチェックをしませんでした。 – Dwilson

+0

あなたがそれを必要とするまで、そのダイアグラムは恐ろしいものです。それは私自身のコードを実際に型チェックしないために得られるものです。 :) –