« NetLogo: Estructuras … « || Inicio || » NetLogo: Interfaz Grá… »

NetLogo: Procedimientos

Última modificación: 7 de Octubre de 2020, y ha tenido 1229 vistas

Etiquetas utilizadas: || || ||

Comandos: Procedimientos, Acciones y Funciones

NetLogo también permite la construcción de nuestros propios comandos. El uso más común es el de las acciones, que son como guiones que agrupan en unidades lógicas un conjunto de comandos que se repite habitualmente, lo que facilita su ejecución y modificación en caso de necesidad. Se definen de la siguiente forma:

to nombre-accion [parametro1 parametro2 ... parametron] 
comando-1
comando-2
comando-3
...
end

Para llamar una rutina se usa directamente su nombre junto con los valores asociados a los parámetros de entrada.

Las funciones (también llamados reportes) son otra forma de agrupar comandos, con la diferencia de que devuelven un valor:

to-report nombre-funcion [parametro1 parametro2 ... parametron]
    comando-1
    comando-2
    ...
    report val
end

Por ejemplo:

to-report cuadrado [ x ] 
report x*x
end

Normalmente, en NetLogo suelen diferenciarse ambos por el tipo depalabra usada. Así, habitualmente las acciones se asocian a verbos (tales como create, die, jump, inspect, clear), mientras que los reporters son nombres o frases.

En general, los comandos que vienen construidos en NetLogo de fábrica se llaman primitivas, mientras que aquellos que define el usuario para un modelo concreto se llaman procedimientos. Cada procedimiento se define por un nombre precedido de la palabra clave to (o to-report en el caso de las funciones) y acaba con la palabra clave end.

Tanto los comandos como los reportes pueden recibir entradas que puede usar para llevar a cabo la acción o cálculo que desarrolla.

En NetLogo debes especificar que conjunto de agentes debe ejecutar cada comando, en caso contrario, el sistema presupone que el comando debe ser ejecutado por el observador. Hay comandos (como ca y crt) que solo pueden ser ejecutados por el observador, otros (como fd) solo por las tortugas, y otros (como set) que pueden ser ejecutados por todos los tipos de agentes.

Procedimientos con entrada

Para crear un procedimiento que acepta argumentos de entrada basta incluir una lista con los nombres con los que se usarán en su ejecución tras el nombre del procedimiento. Por ejemplo:

to dibuja-poligono [num-caras longitud]
    pd
    repeat num-caras [
      fd longitud
      rt (360 / num-caras)
] end

Una vez definido, en cualquier otra parte del código del modelo puedes usar el procedimiento, por ejemplo:

ask turtles [dibuja-poligono 8 who]

que, en este caso, hará que cada tortuga dibuje un octógono de lado igual a su identificador.

Procedimientos con salida

Para definir un reporte se sigue un método similar a los procedimientos normales, salvo que se usa el comando to-report para su definición, y en el cuerpo del procedimiento se usa el comando report para devolver el valor requerido. Por ejemplo:

to-report valor-abs [numero]
  if-else number >= 0
    [report number]
    [report 0 - number]
end

Procedimientos Anónimos

Los procedimientos anónimos permiten almacenar código que se ejecutará más tarde (o definir pequeños comandos que no requieren de un nombre para su uso inmediato, como veremos un poco más adelante). Al igual que los procedimientos normales de NetLogo, un procedimiento anónimo puede ser una acción o un reporte.

Los procedimientos anónimos son valores, lo que significa que pueden transmitirse como entrada, notificarse como resultado o almacenarse en una variable y, en consecuencia, no se pueden aplicar directamente sobre datos de entrada (necesitaremos un artificio para ello). Esta característica hace que esta capacidad de crear procedimientos anónimos y tratarlos como datos aproxima a NetLogo un paso más a los lenguajes funcionales, y permite (junto con algunas primitivas que veremos después) reescribir costosos procedimientos de una forma más directa, ahorradora, y segura.

Un procedimiento anónimo, al ser únicamente el cuerpo de un procedimiento, puede ejecutarse una vez, varias veces o no hacerlo en absoluto. En otros lenguajes de programación, los procedimientos anónimos se conocen como funciones de primera clase, cierres o lambda.

Primitivas de Procedimientos Anónimos

Las primitivas específicas relacionadas con los procedimientos anónimos son:

 -> , is-anonymous-command?,  is-anonymous-reporter?

-> permite crear un procedimiento anónimo (acción o reporte). Por ejemplo,

[ -> fd 2 ] 

genera una acción anónima, porque fd es una acción, mientras que

[ -> count turtles ] 

devuelve un reporte anónimo, porque count es un reporte.

Hay primitivas de NetLogo que requieren procedimientos anónimos como entrada:

foreach, map, reduce, filter, n-values, sort-by

Sin embargo, y como veremos los ejemplos iniciales que trabajan sobre listas en el siguiente apartado, puede no ser necesario usar -> si el procedimiento anónimo contiene una primitiva simple que solo requiere los datos directos que le pasa la primitiva correspondiente. Por ejemplo, podemos escribir:

foreach lista show

en vez de:

foreach lista [ [x] -> show x ]

aunque esta última opción también es correcta.

Para ejecutar un procedimiento anónimo sobre datos de entrada se pueden usar las primitivas run (para el caso de acciones anónimas) y run-result (para el caso de reportes anónimos), y ambos pueden recibir los datos de entrada que el procedimiento anónimo espera. Su forma general es:

(run accion-anonimo par1 ... parN) 
(run-result reporte-anonimo par1 ... parN)

Si no se pasan parámetros adicionales, porque el procedimiento anónimo no los necesita, entonces se pueden evitar los paréntesis exteriores.

Parámetros de entrada para los Procedimientos Anónimos

  • Si el procedimiento anónimo no recibe datos de entrada:
[ -> comandos ]
  • Si el procedimiento anónimo recibe un único dato de entrada:
[ x -> comandos (que usan x) ]
  • Si el procedimiento anónimo usa 2 o más datos de entrada:
[ [x1 ... xn] -> comandos (que usan x1 ... xn) ]

Por ejemplo:

[ -> show "Anuncio" ] 
[ x -> 2 * (x + 1) ]
[ [x y] -> ask x [ rt y ] ]

Cuando se usan procedimientos simples en las primitivas anteriores se puede usar una sintaxis más concisa que facilita la comprensión del código, por ejemplo:

map abs [1 -2 3 -4] = map [x -> abs x] [1 -2 3 -4] => [1 2 3 4] 
reduce + [1 2 3 4] = reduce [[ x y] -> x + y] [1 2 3 4] => 10
filter is-number? [1 "x" 3] = filter [x -> is-number? x] [1 "x" 3] => [1 3]
foreach [1 2 3 4] print = foreach [1 2 3 4] [x -> print x] => imprime desde 1 hasta 4

Se deben tener en cuenta algunas limitaciones actuales (que podrán ser eliminadas en versiones posteriores):

  • Los procedimientos anónimos no pueden aceptar una cantidad variable de entradas.
  • Los reportes anónimos solo pueden contener expresiones simples "de una línea". Por ejemplo, se debe usar ifelse-valuet, y no if, y no se debe usar la primitiva report. Si el código que se desea usar es demasiado complejo, se recomienda (o puede ser imprescindible) usar un reporte definido para tal fin, y llamarlo desde el reporte anónimo.
  • Solo las primitivas referenciadas anteriormente pueden admitir procedimientos anónimos, por lo que no sustituyen a bloques de comandos en otros contextos.
  • La sintaxis concisa explicitada anteriormente solo es válida para esas primitivas (o para primitivas de extensiones que se hayan definido de forma adecuada para ello), pero no para procedimientos normales desarrollados por el usuario.

« NetLogo: Estructuras … « || Inicio || » NetLogo: Interfaz Grá… »