10

私はこれらのデータ型を持っています:

data PointPlus = PointPlus
    { coords :: Point
    , velocity :: Vector
    } deriving (Eq)

data BodyGeo = BodyGeo
    { pointPlus :: PointPlus
    , size :: Point
    } deriving (Eq)

data Body = Body
    { geo :: BodyGeo
    , pict :: Color
    } deriving (Eq)

これは、私のゲームのキャラクター、敵、オブジェクトなどの基本データ型です (現在、プレイヤーと地面として 2 つの四角形しかありません:p)。

キーを押すと、キーを変えることで文字が左右に移動したり、ジャンプしたりしvelocityます。に を追加することで移動が行われvelocityますcoords。現在、以下のように書かれています。

move (PointPlus (x, y) (xi, yi)) = PointPlus (x + xi, y + yi) (xi, yi)

私は全体ではなくPointPlus私の一部を取っているだけです。それ以外の場合は次のようになります。BodyBody

move (Body (BodyGeo (PointPlus (x, y) (xi, yi)) wh) col) = (Body (BodyGeo (PointPlus (x + xi, y + yi) (xi, yi)) wh) col)

の最初のバージョンのmove方が優れていますか? とにかく、movechanges のみの場合PointPlus、 new 内でそれを呼び出す別の関数が必要Bodyです。update説明します:ゲームの状態を更新するために呼び出される関数があります。現在のゲームの状態 (Body今のところ単一) が渡され、更新された が返されBodyます。

update (Body (BodyGeo (PointPlus xy (xi, yi)) wh) pict) = (Body (BodyGeo (move (PointPlus xy (xi, yi))) wh) pict)

それは私をくすぐります。. _ Body_ PointPlusこの完全な「再構築」を手動で回避する方法はありますか? のように:

update body = backInBody $ move $ pointPlus body

backInBodyもちろん、を定義する必要はありません。

4

1 に答える 1

14

あなたが探しているのは「レンズ」です。レンズにはいくつかの異なるパッケージがあります。ここにそれらの良い要約があります。

私の理解では、aあるフィールドのデータ型のレンズbは 2 つの操作を提供baますb。したがって、レンズを使用して、深くネストされた を操作しPointPlusます。

lens パッケージは、レンズを操作するための便利な関数と、非常に便利なレンズを (テンプレート Haskell を使用して) 自動的に生成する方法を提供します。

特に、データ型の構造のおかげで、他の場所でのネストで同様の問題が発生する可能性が高いため、プロジェクトを検討する価値があると思います。

于 2012-06-10T10:24:02.387 に答える