Trilhas
/
Factor
Factor
/
Exercícios
/
Coleta no jardim
Coleta no jardim

Coleta no jardim

Exercício de aprendizagem

Introdução

Às vezes, um pedaço de estado precisa ser compartilhado entre várias palavras, sem que você fique passando esse estado pelos efeitos de pilha delas toda vez. As variáveis dinâmicas do Factor, declaradas com SYMBOL:, dão a cada palavra acesso a um valor guardado em um namespace.

SYMBOL: e SYMBOLS:

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

USING: namespaces ;

SYMBOLS: counter total ;

Definir e obter

set-global e get-global (em namespaces) operam sobre o namespace 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 no nível do módulo, as variantes com -global são o que você quer.

Associações com escopo com with-variable

Uma variável dinâmica também aceita uma segunda variante, com escopo. set / get / change (sem o sufixo -global) leem e escrevem o escopo dinâmico atual, e with-variable (em namespaces) cria um escopo novo enquanto uma quotation estiver em execução:

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

A variável fica associada a value enquanto quot roda; quando ele retorna, a associação desaparece. Isso permite que quem chama de fora "injete" um valor que o código interno consegue ler, sem passá-lo 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 você lê o código de outras pessoas.

Vetores mutáveis

Como as variáveis dinâmicas guardam uma referência, você pode manter uma coleção mutável dentro de uma delas e atualizá-la no lugar:

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. Sempre use clone em um literal V{ } antes de guardá-lo: os literais são compartilhados entre chamadas.

find: a primeira correspondência

find (em sequences) retorna o primeiro elemento para o qual um predicado é verdadeiro, junto com o índice dele:

find ( seq quot -- index elt/f )

Se nada corresponder, os dois valores são f. Descartar o índice com nip e usar unless* é a combinação padrão de "valor padrão se faltar".

reject: descarte as correspondências

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

Instruções

A associação de moradores está pedindo que você cuide dos registros dos canteiros do jardim. O estado fica em duas variáveis dinâmicas:

  • registrations: um vetor de tuplas plot registradas no momento para uma pessoa.
  • next-id: o inteiro que será usado no próximo registro.

A tupla plot tem duas fendas:

fenda tipo
id inteiro
registered-to string

1. Abra o jardim e liste os registros

Defina open-garden para inicializar as variáveis dinâmicas: um vetor vazio para registrations e 1 para next-id. Depois, defina list-registrations para retornar o vetor atual de canteiros.

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

2. Registre um canteiro

Defina register para retirar um nome da pilha, montar um novo plot com o próximo id disponível, adicioná-lo ao vetor registrations, incrementar next-id em um e retornar o novo canteiro.

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 canteiros devem ser únicos e continuar crescendo mesmo depois de uma liberação: next-id nunca deve reutilizar um valor.

3. Libere um canteiro

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

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

4. Obtenha um canteiro registrado

Defina get-registration para receber um id e retornar o canteiro correspondente, ou o símbolo not-found se nenhum canteiro tiver esse id.

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

7 get-registration .
! => not-found

5. Encontre canteiros por nome

Defina find-by-name para receber um nome e retornar um vetor com todos os canteiros registrados no momento para 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 O link abre em uma nova janela ou aba
Factor Exercism

Tudo pronto para começar Coleta no jardim?

Crie sua conta no Exercism para aprender e dominar Factor com 47 conceitos163 exercícios e mentoria humana de verdade, tudo de graça.