À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 ;
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.
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.
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ênciafind (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ênciasreject (também em sequences) é o oposto de filter: retorna os elementos que não passam no predicado.
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 |
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{ }
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.
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{ }
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
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" } } }
Crie sua conta no Exercism para aprender e dominar Factor com 47 conceitos163 exercícios e mentoria humana de verdade, tudo de graça.