2012-06-10 6 views
10

Ho questi tipi di dati:Haskell: "quanto" di tipo dovrebbe ricevere le funzioni? ed evitando completa "ricostruzione"

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) 

E 'il tipo di dati di base per i personaggi, nemici, oggetti, ecc nel mio gioco (beh, devo solo due rettangoli come il giocatore e il terreno adesso: p).

Quando un tasto, i caratteri si spostano a destra, a sinistra o salta cambiando il suo velocity. Lo spostamento viene effettuato aggiungendo velocity allo coords. Attualmente, è scritto come segue:

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

Sto solo prendendo la parte PointPlus della mia Body e non l'intero Body, altrimenti sarebbe:

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

è la prima versione di move meglio ? Ad ogni modo, se move cambia solo PointPlus, ci deve essere un'altra funzione che la chiama all'interno di un nuovo Body. Spiego: c'è una funzione update che viene chiamata per aggiornare lo stato del gioco; viene passato lo stato attuale del gioco, un singolo Body per ora e restituisce l'aggiornamento Body.

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

Che mi fa il solletico. Tutto è mantenuto lo stesso all'interno di Body eccetto lo PointPlus. C'è un modo per evitare questa "ricostruzione" completa a mano? Come in:

update body = backInBody $ move $ pointPlus body 

senza dover definire backInBody, naturalmente.

risposta

14

Siete alla ricerca di "lenti". Ci sono diversi pacchetti per obiettivi; here è un buon riassunto di loro.

mia comprensione è che una lente su un tipo di dati a per qualche campo b fornisce due operazioni: un modo per ottenere il valore di b e un modo per ottenere un nuovo a con un valore diverso di b. Quindi useresti solo una lente per lavorare con lo PointPlus profondamente annidato.

Le confezioni delle lenti forniscono utili funzioni per il lavoro con gli obiettivi e modi per generare automaticamente obiettivi (con modello Haskell) che potrebbero essere molto convenienti.

Penso che valga la pena esaminare il progetto, soprattutto perché è probabile che si incontrino problemi simili con l'annidamento in altri luoghi grazie alla struttura dei tipi di dati.

+0

Questo è perfetto, soprattutto con la generazione automatica! E la funzione 'move'? È meglio prendere l'intero 'Body' o solo la sua parte' PointPlus'? – L01man

+3

@ L01man Descrivo anche un esempio concreto molto simile al tuo in un post sul mio blog sugli obiettivi [qui] (http://www.haskellforall.com/2012/01/haskell-for-mainstream-programmers_28.html) –

+0

La tua spiegazione passo-passo mi ha aiutato a capire pienamente le lenti. – L01man

Problemi correlati