Avrei potuto memorizzare gli indici di poligono nella scena corrente, l'indice del punto trascinato in poligono e sostituirlo ogni volta. Ma questo approccio non si ridimensiona - quando i livelli di composizione vanno a 5 e oltre, la piastra di cottura diventerebbe insopportabile.
Hai assolutamente ragione, questo approccio non si ridimensiona se non riesci a aggirare la piastra della caldaia . In particolare, la piastra di caldaia per la creazione di una scena completamente nuova con un piccolo sottoparte è cambiata. Tuttavia, molti linguaggi funzionali forniscono un costrutto per affrontare questo tipo di manipolazione della struttura nidificata: le lenti.
Un obiettivo è fondamentalmente un getter e setter per dati immutabili. Un obiettivo è focalizzato su una piccola parte di una struttura più grande. Data una lente, ci sono due cose che puoi fare con essa: puoi visualizzare la piccola parte di un valore della struttura più grande oppure puoi impostare la piccola parte di un valore di una struttura più grande su un nuovo valore. Ad esempio, supponiamo di avere un obiettivo focalizzato sul terzo elemento in un elenco:
thirdItemLens :: Lens [a] a
Questo tipo significa che la struttura più grande è un elenco di cose e la sottoparte piccola è una di quelle cose. Dato questo obiettivo, è possibile visualizzare e impostare il terzo elemento nell'elenco:
> view thirdItemLens [1, 2, 3, 4, 5]
3
> set thirdItemLens 100 [1, 2, 3, 4, 5]
[1, 2, 100, 4, 5]
Il motivo per cui gli obiettivi sono utili è perché sono valori che rappresentano getter e setter e puoi astrarre su di essi nello stesso modo in cui puoi fare altri valori. È possibile creare funzioni che restituiscono obiettivi, ad esempio una listItemLens
funzione che accetta un numero n
e restituisce un obiettivo che visualizza l' n
elemento th in un elenco. Inoltre, gli obiettivi possono essere composti :
> firstLens = listItemLens 0
> thirdLens = listItemLens 2
> firstOfThirdLens = lensCompose firstLens thirdLens
> view firstOfThirdLens [[1, 2], [3, 4], [5, 6], [7, 8]]
5
> set firstOfThirdLens 100 [[1, 2], [3, 4], [5, 6], [7, 8]]
[[1, 2], [3, 4], [100, 6], [7, 8]]
Ogni obiettivo incapsula il comportamento per attraversare un livello della struttura dei dati. Combinandoli, è possibile eliminare il boilerplate per attraversare più livelli di strutture complesse. Ad esempio, supponendo di avere un punto di scenePolygonLens i
visualizzazione del i
poligono in una scena e un punto di polygonPointLens n
vista del nth
punto in un poligono, puoi creare un costruttore di obiettivi per concentrarti solo sul punto specifico a cui tieni in un'intera scena in questo modo:
scenePointLens i n = lensCompose (polygonPointLens n) (scenePolygonLens i)
Supponiamo ora che un utente faccia clic sul punto 3 del poligono 14 e lo sposta di 10 pixel a destra. Puoi aggiornare la tua scena in questo modo:
lens = scenePointLens 14 3
point = view lens currentScene
newPoint = movePoint 10 0 point
newScene = set lens newPoint currentScene
Questo contiene bene tutto il boilerplate per attraversare e aggiornare una scena all'interno lens
, tutto ciò di cui ti devi preoccupare è quello a cui vuoi cambiare il punto. Puoi astrarre ulteriormente questo con una lensTransform
funzione che accetta un obiettivo, un obiettivo e una funzione per aggiornare la vista dell'obiettivo attraverso l'obiettivo:
lensTransform lens transformFunc target =
current = view lens target
new = transformFunc current
set lens new target
Questo accetta una funzione e la trasforma in un "programma di aggiornamento" su una struttura di dati complicata, applicando la funzione solo alla vista e utilizzandola per costruire una nuova vista. Quindi tornando allo scenario di spostare il 3 ° punto del 14 ° poligono a 10 pixel a destra, che può essere espresso in questo lensTransform
modo:
lens = scenePointLens 14 3
moveRightTen point = movePoint 10 0 point
newScene = lensTransform lens moveRightTen currentScene
E questo è tutto ciò che serve per aggiornare l'intera scena. Questa è un'idea molto potente e funziona molto bene quando hai delle belle funzioni per costruire obiettivi che visualizzano i pezzi dei tuoi dati che ti interessano.
Tuttavia, questo è tutto roba abbastanza là fuori al momento, anche nella comunità di programmazione funzionale. È difficile trovare un buon supporto di libreria per lavorare con gli obiettivi, e ancora più difficile spiegare come funzionano e quali sono i vantaggi per i tuoi colleghi. Prendi questo approccio con un granello di sale.