Rutas
/
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 fragmento de estado debe compartirse entre varias palabras sin tener que pasarlo cada vez por sus efectos de pila. Las variables dinámicas de Factor, declaradas con SYMBOL:, dan a cada palabra 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.

Vinculaciones con scope mediante with-variable

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

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

La variable queda vinculada a value mientras se ejecuta quot; en cuanto este termina, la vinculación desaparece. Esto permite que quien llama desde fuera «inyecte» un valor que el código interno puede leer sin 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 set/get/change resulta útil cuando lees el código de otras personas.

Vectores mutables

Como las variables dinámicas mantienen una referencia, puedes guardar una colección mutable dentro de una y actualizarla in situ:

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. Haz siempre 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 que un predicado se evalúa como verdadero, junto con 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: descartar las coincidencias

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

Instrucciones

Tu asociación vecinal te pide que gestiones las inscripciones 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 debe usar para la siguiente inscripción.

La tupla plot tiene dos ranuras:

ranura tipo
id integer
registered-to string

1. Abre el jardín y lista sus inscripciones

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 de parcelas actual.

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, añadirla al vector registrations, incrementar next-id en uno y devolver la nueva plot.

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 id de las parcelas deben ser únicos y aumentar incluso después de liberar una parcela: next-id nunca debe reutilizar un valor.

3. Libera una parcela

Define release para tomar un id y eliminar de registrations la entrada correspondiente. 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 correspondiente, 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 pestaña nueva
Factor Exercism

¿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.