Ich hätte die Indizes von Polygon in der aktuellen Szene und den Index des gezogenen Punkts in Polygon speichern und jedes Mal ersetzen können. Dieser Ansatz lässt sich jedoch nicht skalieren. Wenn die Zusammensetzung auf 5 und höher steigt, wird die Kesselplatte unerträglich.
Sie haben absolut Recht, dieser Ansatz lässt sich nicht skalieren, wenn Sie die Kesselplatte nicht umgehen können . Insbesondere wurde die Boilerplate zum Erstellen einer ganz neuen Szene mit einem winzigen Teil geändert. Viele funktionale Sprachen bieten jedoch ein Konstrukt für den Umgang mit dieser Art der Manipulation verschachtelter Strukturen: Linsen.
Ein Objektiv ist im Grunde ein Getter und Setter für unveränderliche Daten. Ein Objektiv konzentriert sich auf einen kleinen Teil einer größeren Struktur. Bei einer Linse gibt es zwei Dinge , die man damit machen kann - man kann sieht den kleinen Teil eines Wertes der größeren Struktur, oder Sie können festlegen , den kleinen Teil eines Wertes einer größeren Struktur auf einen neuen Wert. Angenommen, Sie haben ein Objektiv, das sich auf das dritte Element in einer Liste konzentriert:
thirdItemLens :: Lens [a] a
Dieser Typ bedeutet, dass die größere Struktur eine Liste von Dingen ist und der kleine Unterabschnitt eines dieser Dinge ist. Mit diesem Objektiv können Sie das dritte Element in der Liste anzeigen und festlegen:
> view thirdItemLens [1, 2, 3, 4, 5]
3
> set thirdItemLens 100 [1, 2, 3, 4, 5]
[1, 2, 100, 4, 5]
Der Grund, warum Objektive nützlich sind, liegt darin, dass sie Werte darstellen, die Getter und Setter darstellen, und dass Sie sie genauso abstrahieren können wie andere Werte. Sie können Funktionen erstellen, die Objektive zurückgeben, z. B. eine listItemLens
Funktion, die eine Zahl n
akzeptiert und ein Objektiv zurückgibt, das das n
dritte Element in einer Liste anzeigt. Zusätzlich können Linsen zusammengesetzt werden :
> 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]]
Jedes Objektiv kapselt das Verhalten zum Durchlaufen einer Ebene der Datenstruktur. Indem Sie sie kombinieren, können Sie die Kesselplatte für das Durchqueren mehrerer Ebenen komplexer Strukturen entfernen. Angenommen, Sie haben eine scenePolygonLens i
, die das i
dritte Polygon in einer Szene anzeigt, und eine polygonPointLens n
, die den nth
Punkt in einem Polygon anzeigt, können Sie einen Linsenkonstruktor erstellen, um sich auf genau den Punkt zu konzentrieren, den Sie in einer gesamten Szene interessieren:
scenePointLens i n = lensCompose (polygonPointLens n) (scenePolygonLens i)
Angenommen, ein Benutzer klickt auf Punkt 3 des Polygons 14 und verschiebt ihn um 10 Pixel nach rechts. Sie können Ihre Szene folgendermaßen aktualisieren:
lens = scenePointLens 14 3
point = view lens currentScene
newPoint = movePoint 10 0 point
newScene = set lens newPoint currentScene
Dies enthält die gesamte Boilerplate zum Durchlaufen und Aktualisieren einer Szene im Inneren lens
. Alles, was Sie beachten müssen, ist, auf was Sie den Punkt ändern möchten. Sie können dies mit einer lensTransform
Funktion weiter abstrahieren , die ein Objektiv, ein Ziel und eine Funktion zum Aktualisieren der Ansicht des Ziels durch das Objektiv akzeptiert :
lensTransform lens transformFunc target =
current = view lens target
new = transformFunc current
set lens new target
Dies nimmt eine Funktion und verwandelt sie in einen "Updater" für eine komplizierte Datenstruktur, wobei die Funktion nur auf die Ansicht angewendet und zum Erstellen einer neuen Ansicht verwendet wird. Kehren wir also zu dem Szenario zurück, in dem der 3. Punkt des 14. Polygons um 10 Pixel nach rechts verschoben wird. Dies kann folgendermaßen ausgedrückt lensTransform
werden:
lens = scenePointLens 14 3
moveRightTen point = movePoint 10 0 point
newScene = lensTransform lens moveRightTen currentScene
Und das ist alles, was Sie brauchen, um die gesamte Szene zu aktualisieren. Dies ist eine sehr leistungsstarke Idee und funktioniert sehr gut, wenn Sie einige nützliche Funktionen zum Erstellen von Objektiven haben, mit denen Sie die Daten anzeigen können, die Ihnen wichtig sind.
Allerdings ist dies derzeit alles ziemlich weit draußen, selbst in der funktionalen Programmier-Community. Es ist schwierig, eine gute Bibliotheksunterstützung für die Arbeit mit Objektiven zu finden, und noch schwieriger zu erklären, wie sie funktionieren und welche Vorteile sie für Ihre Mitarbeiter haben. Nehmen Sie diesen Ansatz mit einem Körnchen Salz.