Tracks
/
Factor
Factor
/
Ejercicios
/
Reunión en el jardín
Reunión en el jardín

Reunión en el jardín

Ejercicio de aprendizaje

Introducción

A veces un dato de estado necesita compartirse entre varios words sin tener que pasarlo por sus efectos de pila cada vez. Las variables dinámicas de Factor, declaradas con SYMBOL:, le dan a cada word acceso a un valor almacenado en un espacio de nombres.

SYMBOL: y SYMBOLS:

SYMBOL: name declara una variable. SYMBOLS: a b c ; declara varias a la vez:

USING: namespaces ;

SYMBOLS: counter total ;

Establecer y obtener

set-global y get-global (en namespaces) operan sobre el espacio de nombres 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 el estado a nivel de módulo, las variantes -global son las que necesitas.

Enlaces con ámbito con with-variable

Una variable dinámica también admite una segunda variante, con ámbito. set / get / change (sin el sufijo -global) leen y escriben el ámbito dinámico actual, y with-variable (en namespaces) crea un ámbito nuevo mientras dura una quotation:

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

La variable queda enlazada a value mientras se ejecuta quot; cuando este termina, el enlace desaparece. Esto permite que quien llama desde afuera «inyecte» un valor que el código interno puede leer sin tener que pasarlo por cada firma de pila.

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 ejercicio usa la variante global en todo momento, pero reconocer la familia paralela de set/get/change es útil cuando lees código de otras personas.

Vectores mutables

Como las variables dinámicas guardan una referencia, puedes mantener una colección mutable dentro de una de ellas y actualizarla en el mismo 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{ … } es un vector literal. Siempre haz clone de un literal V{ } antes de guardarlo: los literales se comparten entre llamadas.

find: la primera coincidencia

find (en sequences) devuelve el primer elemento para el cual un predicado es verdadero, además de su índice:

find ( seq quot -- index elt/f )

Si nada coincide, ambos valores son f. Descartar el índice con nip y usar unless* es la combinación estándar de «valor por defecto si falta».

reject: descarta las coincidencias

reject (también en sequences) es lo opuesto de filter: devuelve los elementos que no cumplen el predicado.

Instrucciones

La asociación de tu comunidad te pide que administres los registros de parcelas del jardín. El estado se guarda en dos variables dinámicas:

  • registrations — un vector de tuplas plot asignadas actualmente a una persona.
  • next-id — el entero que se usará para el próximo registro.

La tupla plot tiene dos campos:

campo tipo
id integer
registered-to string

1. Abre el jardín y lista sus registros

Define open-garden para inicializar las variables dinámicas: un vector vacío para registrations y 1 para next-id. Después define list-registrations para devolver el vector actual de parcelas.

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

2. Registra una parcela

Define register para tomar un nombre de la pila, construir una plot nueva con el siguiente id disponible, agregarla al vector registrations, aumentar next-id en uno y devolver la nueva parcela.

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

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

Los ids de las parcelas deben ser únicos y seguir aumentando incluso después de liberar una. next-id nunca debe reutilizar un valor.

3. Libera una parcela

Define release para tomar un id y eliminar de registrations la entrada que coincida. Liberar un id desconocido no tiene ningún efecto.

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

4. Obtén una parcela registrada

Define get-registration para tomar un id y devolver la parcela que coincida, o el símbolo not-found si ninguna parcela tiene ese id.

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

7 get-registration .
! => not-found

5. Busca parcelas por nombre

Define find-by-name para tomar un nombre y devolver un vector con todas las parcelas registradas actualmente a nombre de esa 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" } } }
Editar en GitHub El enlace se abre en una ventana o una pestaña nuevas
Factor Exercism

¿Todo listo para empezar Reunión en el jardín?

Regístrate en Exercism para aprender y dominar Factor con 47 conceptos163 ejercicios y mentoría humana real, todo gratis.