Track
/
Factor
Factor
/
Esercizi
/
Raccolta in giardino
Raccolta in giardino

Raccolta in giardino

Esercizio di apprendimento

Introduzione

A volte una parte di stato deve essere condivisa tra diverse word senza doverla passare ogni volta attraverso i loro stack effect. Le variabili dinamiche di Factor, dichiarate con SYMBOL:, danno a ogni word accesso a un valore conservato in un namespace.

SYMBOL: e SYMBOLS:

SYMBOL: name dichiara una variabile. SYMBOLS: a b c ; ne dichiara diverse in una sola volta:

USING: namespaces ;

SYMBOLS: counter total ;

Impostare e leggere

set-global e get-global (in namespaces) operano sul namespace globale:

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

Per lo stato a livello di modulo, le varianti -global sono quelle che ti servono.

Associazioni con scope tramite with-variable

Una variabile dinamica supporta anche una seconda variante, quella con scope. set / get / change (senza il suffisso -global) leggono e scrivono nello scope dinamico corrente, e with-variable (in namespaces) crea uno scope nuovo per la durata di una quotation:

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

La variabile è legata a value mentre quot viene eseguita; quando questa termina, il legame scompare. Così chi chiama dall'esterno può «iniettare» un valore che il codice interno può leggere senza doverlo passare attraverso ogni stack signature.

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)

In questo esercizio useremo la variante globale dall'inizio alla fine, ma riconoscere la famiglia parallela set/get/change è utile quando leggi il codice di altre persone.

Vettori mutabili

Dato che le variabili dinamiche contengono un riferimento, puoi conservare una collezione mutabile dentro una di esse e aggiornarla sul posto:

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{ … } è un vettore letterale. Fai sempre clone di un letterale V{ } prima di memorizzarlo: i letterali sono condivisi tra le chiamate.

find: la prima corrispondenza

find (in sequences) restituisce il primo elemento per cui un predicato risulta vero, insieme al suo indice:

find ( seq quot -- index elt/f )

Se non c'è nessuna corrispondenza, entrambi i valori sono f. Scartare l'indice con nip e usare unless* è la combinazione standard per il «valore predefinito se manca qualcosa».

reject: scartare le corrispondenze

reject (sempre in sequences) è l'opposto di filter: restituisce gli elementi che non superano il predicato.

Istruzioni

La tua associazione di quartiere ti chiede di gestire le registrazioni degli appezzamenti del giardino. Lo stato è contenuto in due variabili dinamiche:

  • registrations: un array di tuple plot attualmente assegnate a una persona.
  • next-id: l'intero da usare per la prossima registrazione.

La tupla plot ha due campi:

campo tipo
id intero
registered-to stringa

1. Apri il giardino ed elenca le sue registrazioni

Definisci open-garden per inizializzare le variabili dinamiche: un array vuoto per registrations e 1 per next-id. Poi definisci list-registrations per restituire l'array attuale degli appezzamenti.

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

2. Registra un appezzamento

Definisci register per prendere un nome dallo stack, costruire un nuovo appezzamento con il prossimo id disponibile, aggiungerlo in coda all'array registrations, incrementare next-id di uno e restituire il nuovo appezzamento.

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

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

Gli id degli appezzamenti devono essere univoci e sempre crescenti, anche dopo un rilascio: next-id non deve mai riutilizzare un valore.

3. Rilascia un appezzamento

Definisci release per prendere un id e rimuovere da registrations la voce corrispondente. Rilasciare un id sconosciuto non ha alcun effetto.

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

4. Ottieni un appezzamento registrato

Definisci get-registration per prendere un id e restituire l'appezzamento corrispondente, oppure il simbolo not-found se nessun appezzamento ha quell'id.

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

7 get-registration .
! => not-found

5. Trova gli appezzamenti per nome

Definisci find-by-name per prendere un nome e restituire un array di tutti gli appezzamenti attualmente registrati a quella persona.

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" } } }
Modifica tramite GitHub Il link si apre in una nuova finestra o scheda
Factor Exercism

Vuoi iniziare Raccolta in giardino?

Iscriviti a Exercism per imparare e padroneggiare Factor con 47 concetti163 esercizi e il mentoring di persone reali, tutto gratis.