Percursos
/
Factor
Factor
/
Exercícios
/
Encontro no Jardim
Encontro no Jardim

Encontro no Jardim

Exercício de aprendizagem

Introdução

Por vezes, um pedaço de estado tem de ser partilhado entre várias palavras sem ter de ser passado pelos respetivos efeitos de pilha de cada vez. As variáveis dinâmicas do Factor, declaradas com SYMBOL:, dão a cada palavra acesso a um valor guardado num espaço de nomes.

SYMBOL: e SYMBOLS:

SYMBOL: name declara uma variável. SYMBOLS: a b c ; declara várias de uma só vez:

USING: namespaces ;

SYMBOLS: counter total ;

Definir e obter

set-global e get-global (no namespaces) operam sobre o espaço de nomes global:

set-global    ( value variable -- )
get-global    ( variable -- value )
change-global ( variable quot: ( old -- new ) -- )
0 counter set-global
counter get-global .         ! => 0
counter [ 10 + ] change-global
counter get-global .         ! => 10

Para estado ao nível do módulo, são as variantes -global que precisas.

Ligações de âmbito com with-variable

Uma variável dinâmica também suporta uma segunda variante, com âmbito. set / get / change (sem o sufixo -global) leem e escrevem no âmbito dinâmico atual, e with-variable (no namespaces) cria um âmbito novo durante a execução de uma quotation:

with-variable ( value variable quot -- )
set           ( value variable -- )
get           ( variable -- value )
change        ( variable quot: ( old -- new ) -- )

A variável fica ligada a value enquanto quot está a correr; assim que este termina, a ligação desaparece. Isto permite que um chamador exterior «injete» um valor que o código interior consegue ler sem o passar por todas as assinaturas de pilha.

SYMBOL: greeting

"Hello" greeting [
    greeting get .                ! => "Hello"
    "Howdy" greeting set
    greeting get .                ! => "Howdy"
    greeting [ "!" append ] change
    greeting get .                ! => "Howdy!"
] with-variable

greeting get-global .    ! => f   (the scoped binding is gone)

Este exercício usa a variante global do início ao fim, mas reconhecer a família paralela set/get/change é útil quando lês código de outras pessoas.

Vetores mutáveis

Como as variáveis dinâmicas guardam uma referência, podes manter uma coleção mutável dentro de uma delas e atualizá-la no próprio local:

SYMBOL: history

V{ } clone history set-global
"first event" history get-global push
"second event" history get-global push
history get-global .
! => V{ "first event" "second event" }

V{ … } é um vetor literal. Faz sempre clone de um literal V{ } antes de o guardares: os literais são partilhados entre chamadas.

find: primeira correspondência

find (em sequences) devolve o primeiro elemento para o qual um predicado é verdadeiro, juntamente com o seu índice:

find ( seq quot -- index elt/f )

Se nada corresponder, ambos os valores são f. Descartar o índice com nip e usar unless* é a combinação habitual de «valor predefinido se faltar».

reject: descartar as correspondências

reject (também em sequences) é o oposto de filter: devolve os elementos que não passam no predicado.

Instruções

A associação do teu bairro está a pedir-te para gerires as inscrições dos lotes do jardim. O estado vive em duas variáveis dinâmicas:

  • registrations, um vetor de tuplos plot atualmente atribuídos a uma pessoa.
  • next-id, o número inteiro a usar para a próxima inscrição.

O tuplo plot tem duas fendas:

fenda tipo
id inteiro
registered-to string

1. Abrir o jardim e listar as inscrições

Define open-garden para inicializar as variáveis dinâmicas: um vetor vazio para registrations e 1 para next-id. De seguida, define list-registrations para devolver o vetor de lotes atual.

open-garden
list-registrations .
! => V{ }

2. Registar um lote

Define register para retirar um nome da pilha, construir um plot novo com o próximo id disponível, acrescentá-lo ao vetor registrations, aumentar next-id em uma unidade e devolver o novo lote.

open-garden
"Emma Balan" register .
! => T{ plot { id 1 } { registered-to "Emma Balan" } }

list-registrations .
! => V{ T{ plot { id 1 } { registered-to "Emma Balan" } } }

Os ids dos lotes têm de ser únicos e aumentar mesmo depois de uma libertação: o next-id nunca deve reutilizar um valor.

3. Libertar um lote

Define release para receber um id e remover a entrada correspondente de registrations. Libertar um id desconhecido não faz nada.

open-garden
"Emma" register drop
1 release
list-registrations .
! => V{ }

4. Obter um lote registado

Define get-registration para receber um id e devolver o lote correspondente, ou o símbolo not-found se nenhum lote tiver esse id.

open-garden
"Emma" register drop
1 get-registration .
! => T{ plot { id 1 } { registered-to "Emma" } }

7 get-registration .
! => not-found

5. Encontrar lotes por nome

Define find-by-name para receber um nome e devolver um vetor com todos os lotes atualmente atribuídos a essa pessoa.

open-garden
"Emma" register drop
"Bob" register drop
"Emma" register drop
"Emma" find-by-name .
! => V{ T{ plot { id 1 } { registered-to "Emma" } }
        T{ plot { id 3 } { registered-to "Emma" } } }
Editar via GitHub A ligação abre numa nova janela ou separador
Factor Exercism

Estás pronto para começar Encontro no Jardim?

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