2012-06-10 13 views
10

Mam te typy danych:Haskell: "ile" typu powinno odbierać funkcje? i unikanie pełną „odbudowę”

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) 

jest to typ danych baza dla postaci, wrogów, przedmiotów itp w mojej grze (dobrze, mam tylko dwa prostokąty jak odtwarzacz a teraz ziemia: p).

Po naciśnięciu klawisza znaki przesuwają się w prawo, w lewo lub przeskakują, zmieniając jego velocity. Przenoszenie odbywa się przez dodanie velocity do coords. Obecnie, to zapisać następująco:

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

Ja tylko biorąc PointPlus częścią mojego Body a nie cały Body, inaczej byłoby:

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

Czy pierwsza wersja move lepszego ? W każdym razie, jeśli move zmienia się tylko PointPlus, musi istnieć inna funkcja, która wywoła ją wewnątrz nowego Body. Wyjaśniam: istnieje funkcja update, która jest wywoływana w celu aktualizacji stanu gry; jest przekazywany na bieżący stan gry, na razie pojedynczy Body i zwraca zaktualizowaną Body.

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

To mnie łaskocze. Wszystko zachowuje się tak samo w ramach Body z wyjątkiem PointPlus. Czy istnieje sposób na uniknięcie tej całkowitej "rekonstrukcji" ręcznie? Podobnie jak w:

update body = backInBody $ move $ pointPlus body 

Bez konieczności definiowania backInBody, oczywiście.

Odpowiedz

14

Poszukujesz "soczewek". Istnieje kilka różnych pakietów dla soczewek; here to dobre podsumowanie.

moim rozumieniu jest to, że obiektyw o typ a jakiegoś pola b oferuje dwie operacje: sposób, aby uzyskać wartość b i sposób, aby otrzymać nowy a o innej wartości b. Więc używałbyś obiektywu do pracy z głęboko zagnieżdżonym PointPlus.

Pakiety soczewek zapewniają użyteczne funkcje do pracy z soczewkami oraz sposoby generowania soczewek automatycznie (z szablonem Haskell), co może być bardzo wygodne.

Sądzę, że warto się nimi zająć, szczególnie dlatego, że dzięki podobnym strukturom typów danych można napotkać podobne problemy z zagnieżdżaniem w innych miejscach.

+0

To idealne rozwiązanie, zwłaszcza w przypadku automatycznego generowania! Co z funkcją 'move'? Czy lepiej jest wziąć całe "ciało" lub tylko jego część "PointPlus"? – L01man

+3

@ L01man Opisuję również konkretny przykład bardzo podobny do twojego na moim blogu na temat soczewek [tutaj] (http://www.haskellforall.com/2012/01/haskell-for-mainstream-programmers_28.html) –

+0

Twoje szczegółowe instrukcje pomogły mi zrozumieć w pełni obiektywy. – L01man

Powiązane problemy