Eu poderia ter armazenado índices de polígono na cena atual, índice de ponto arrastado em polígono e substituí-lo sempre. Mas essa abordagem não é escalável - quando os níveis de composição vão para 5 e mais, o clichê se tornaria insuportável.
Você está absolutamente certo, essa abordagem não aumenta se você não conseguir contornar o padrão . Especificamente, o clichê para criar uma cena totalmente nova com uma minúscula subparte foi alterado. No entanto, muitas linguagens funcionais fornecem uma construção para lidar com esse tipo de manipulação de estrutura aninhada: lentes.
Uma lente é basicamente um gerador de dados para imutáveis. Uma lente focaliza uma pequena parte de uma estrutura maior. Dada uma lente, há duas coisas que você pode fazer com ela - é possível visualizar a pequena parte de um valor da estrutura maior ou definir a pequena parte de um valor de uma estrutura maior para um novo valor. Por exemplo, suponha que você tenha uma lente focada no terceiro item de uma lista:
thirdItemLens :: Lens [a] a
Esse tipo significa que a estrutura maior é uma lista de itens e a subparte pequena é um deles. Dada essa lente, você pode visualizar e definir o terceiro item da lista:
> view thirdItemLens [1, 2, 3, 4, 5]
3
> set thirdItemLens 100 [1, 2, 3, 4, 5]
[1, 2, 100, 4, 5]
A razão pela qual as lentes são úteis é porque são valores que representam getters e setters, e você pode abstraí-los da mesma maneira que outros valores. Você pode criar funções que retornam lentes, por exemplo, uma listItemLens
função que pega um número n
e retorna uma lente exibindo o n
item em uma lista. Além disso, as lentes podem ser compostas :
> 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]]
Cada lente encapsula o comportamento para atravessar um nível da estrutura de dados. Ao combiná-los, você pode eliminar o padrão para atravessar vários níveis de estruturas complexas. Por exemplo, supondo que você tenha um scenePolygonLens i
que veja o i
polígono em uma cena e um polygonPointLens n
que veja o nth
ponto em um polígono, você pode criar um construtor de lentes para focar apenas o ponto específico de que você gosta em uma cena inteira como:
scenePointLens i n = lensCompose (polygonPointLens n) (scenePolygonLens i)
Agora, suponha que um usuário clique no ponto 3 do polígono 14 e o mova 10 pixels para a direita. Você pode atualizar sua cena da seguinte maneira:
lens = scenePointLens 14 3
point = view lens currentScene
newPoint = movePoint 10 0 point
newScene = set lens newPoint currentScene
Isso contém muito bem todo o padrão para percorrer e atualizar uma cena dentro lens
, tudo com o que você precisa se preocupar é com o que deseja mudar o ponto. Você pode abstrair ainda mais isso com uma lensTransform
função que aceita uma lente, um alvo e uma função para atualizar a visão do alvo através da lente:
lensTransform lens transformFunc target =
current = view lens target
new = transformFunc current
set lens new target
Isso pega uma função e a transforma em um "atualizador" em uma estrutura de dados complicada, aplicando a função apenas à visualização e usando-a para construir uma nova visualização. Voltando ao cenário de mover o terceiro ponto do 14º polígono para os 10 pixels à direita, isso pode ser expresso em termos lensTransform
como:
lens = scenePointLens 14 3
moveRightTen point = movePoint 10 0 point
newScene = lensTransform lens moveRightTen currentScene
E isso é tudo o que você precisa para atualizar toda a cena. Essa é uma ideia muito poderosa e funciona muito bem quando você tem algumas funções interessantes para construir lentes visualizando as partes de seus dados importantes.
No entanto, tudo isso é bastante interessante atualmente, mesmo na comunidade de programação funcional. É difícil encontrar um bom suporte de biblioteca para trabalhar com lentes e ainda mais difícil explicar como elas funcionam e quais são os benefícios para seus colegas de trabalho. Tome esta abordagem com um grão de sal.