Percursos
/
Roc
Roc
/
Exercícios
/
Pessoa com lentes
Pessoa com lentes

Pessoa com lentes

Médio

Instruções

Usa lentes para atualizar registos aninhados (específico de linguagens com dados imutáveis).

Atualizar campos de registos aninhados e imutáveis é um bocado chato. O código para estes casos é tão pesado quanto a estrutura é profunda. Se tiveres, digamos, uma Person, que contém uma Address, que tem uma Street, que tem um Number, atualizar o Number obriga-te a criar uma nova Street com o novo Number, depois uma nova Address com a nova Street e, por fim, uma nova Person com a nova Address. Já estás confuso?

Uma solução para este problema é usar lentes.

Implementa várias funções de acesso a registos usando lentes. O conjunto de testes também te permite não usar lentes, para poderes experimentar abordagens diferentes.

As lentes não são muito usadas em Roc, porque a sintaxe de atualização de registos cobre muito bem a maioria dos casos de uso. Por exemplo, considera este registo aninhado:

bob = { hair: { color: Brown, length: Long }, mouth: Smiling, height: 6.0 }

Agora vamos cortar o cabelo ao Bob:

new_bob = { ..bob, hair: { ..bob.hair, length: Short } }

Não são precisas lentes! Ainda assim, embora as lentes sejam raras em Roc, são comuns noutras linguagens como Haskell e Scala, por isso podes ter curiosidade em saber como se podem implementar em Roc. É também uma boa forma de praticar algumas funcionalidades avançadas de Roc, como tipos parametrizados e registos que contêm funções. De facto, eis uma forma de representar uma lente em Roc:

Lens(whole, part) := {
	get : whole -> part,
	set : whole, part -> whole,
}

Este é um tipo parametrizado: whole e part podem ser quaisquer tipos. Normalmente, whole é um registo, enquanto part pode ser qualquer tipo de campo. O campo get contém uma função que devolve uma part específica do whole dado, enquanto o campo set contém uma função que devolve uma cópia do whole dado, mas com uma part específica substituída pela part dada.

Por exemplo, aqui está uma lente para obter ou definir o cabelo de uma pessoa:

hair_lens = {
	get: |person| person.hair,
	set: |person, hair| { ..person, hair },
}

Podemos usar esta lente para focar o cabelo do Bob, assim:

bob_hair = bob |> hair_lens.get

E podemos mudar-lhe o cabelo assim:

new_hair = { ..bob.hair, length: Short }
new_bob = bob |> (hair_lens.set)(new_hair)

Nota: os parênteses à volta de hair_lens.set são obrigatórios; sem eles, Roc procuraria uma função chamada set no tipo de hair_lens.

As lentes tornam-se especialmente úteis quando começas a compô-las, pois permitem-te obter e definir partes profundamente aninhadas. Isto pode ser feito implementando uma função como esta:

compose : Lens(outer, inner), Lens(inner, part) -> Lens(outer, part)

Depois de implementares esta função, podes usá-la para criar uma lente para o comprimento do cabelo, assim:

length_lens = {
	get: |hair| hair.length,
	set: |hair, length| { ..hair, length },
}
hair_length_lens = compose(hair_lens, length_lens)

Agora já podes dar outro corte de cabelo ao Bob:

set_hair_length = hair_length_lens.set
new_bob = bob |> set_hair_length(Short)

Também podes querer implementar uma função que te permita aplicar qualquer transformação a uma parte aninhada:

over : Lens(whole, part), whole, (part -> part) -> whole

Depois de implementada, podes usar over assim:

cut_hair = |current_length| match current_length {
	Long => Short
	Short => Bald
	Bald => Bald
}
new_bob = hair_length_lens |> over(bob, cut_hair)

Neste exercício, os testes vão verificar que o teu código consegue modificar várias partes aninhadas do seguinte registo aninhado:

test_person : Person
test_person = {
	name: { forenames: "Jane Joanna", surname: "Doe" },
	birth: {
		born_at: { street: "Longway", house_number: 1024, place: "Springfield", country: "United States" },
		born_on: { year: 1984, month: 4, day: 12 },
	},
	address: { street: "Shortlane", house_number: 2, place: "Fallmeadow", country: "Canada" },
}

Recomendamos que passes primeiro os testes com a sintaxe de atualização de registos do Roc e que só depois experimentes usar lentes.

Editar via GitHub A ligação abre numa nova janela ou separador
Roc Exercism

Estás pronto para começar Pessoa com lentes?

Inscreve-te no Exercism para aprenderes e dominares Roc com 125 exercícios, e mentoria humana real, tudo grátis.