向记者提供论据

Supply argument to reporter

以下可能是一道Netlogo的基础编程题。 我想写一些通用的记者,我可以为他们应该报道的内容提供论据。假设如下程序:

turtles-own [
  houses
  cars
]

to setup
  clear-all
  create-turtles 10
  reset-ticks
end

to go
  ask turtles [
    set houses houses + random 2
    set cars cars + random 5
  ]
  
  tick
end

我可以就这样的房子写一个记者:

to-report mean-houses
  report mean [ houses ] of turtles
end

但我想要一个通用报告器,我也可以用它来报告汽车的平均值,如下所示:

to-report means [ param ]
  report mean [ param ] of turtles
end

然而,这并没有按预期工作:

setup
repeat 15 [go]
show means houses

> ERROR: You can't use HOUSES in an observer context, because HOUSES is turtle-only.*

在这种情况下,如何让 Netlogo 评估 param 在海龟的上下文中?我熟悉如何在 R 中执行此操作(例如,通过 tidy evaluation 屏蔽 {{ x }},或更早的引用机制),但不熟悉如何将其转换为 Netlogo。

您可以使用 runresult,前提是您愿意将过程的参数作为字符串传递:

to-report means [varname]
  report mean [runresult varname] of turtles
end

在命令中心试用:

observer> setup
observer> repeat 15 [go]
observer> show means "houses"
observer: 7.4

如错误所述,您正试图将仅海龟变量 (houses) 传递给在观察者上下文中使用的过程,这不起作用,因为 Netlogo 会在实际之前尝试将变量传递给过程运行宁程序。

相反,您可以使用以下代码。在此示例中,您首先使用“of”-primitive 将 houses/cars 变量提取为列表。只有这样你才能将它们传递给观察者 运行 的“手段”过程。

to-report means [ param ]
  report mean param 
end
show means [houses] of turtles
show means [cars] of turtles

NetLogo 方式

<reporter> [ <expression> ] of <agentset>

注意:我在下面使用“代理”,因为这个答案适用于任何 NetLogo 代理,无论是海龟、海龟品种、补丁还是链接。

NetLogo 不是将代理变量(或表达式)传递给过程,然后以某种方式让代理创建一个列表,然后对列表进行操作,而是可以轻松地首先从每个单独评估的表达式中创建列表代理集中的代理,因此您可以将该列表传递给某些记者。语法(如您所知)是:

;; return list of <expression>
;; calculated by each member of agentset
[ expression ] of agentset

所以,如果这是你的记者:

to-report gini [ samples ] 
  ;; samples will be sorted here, don't pre-sort!
  ;; best guess -- please correct if wrong
  ;; source:
  ;; https://en.wikipedia.org/wiki/Gini_coefficient#Calculation
  let n length samples 
  let indexes (range 1 (n + 1))
  let s1 2 * sum (map  [[i y] -> i * y] indexes sort samples)
  let s2 n * sum samples
  let G (s1 / s2) - ((n + 1) / n) 
  report G 
end

然后您可以像这样计算各种措施的基尼系数:

print gini [ measure-1 ] of turtles
print gini [ measure-2 ] of turtles
print gini [ measure-3 ] of turtles

这是有道理的,因为 gini 是一个采用一组样本的函数。这让您可以轻松使用其他亚种群或品种或其他任何东西。

“缩写”语法

我将带您“沿着花园小径前行”,所以如果您喜欢到目前为止所看到的内容,可以到此为止。如果您想笑一笑,请继续阅读。

也许以上内容对您来说太冗长了,您真的非常想摆脱“乌龟”? (即使您以后可能想将通用函数更通用地应用于子群体?)

好吧,你可以。我们可以使用“匿名记者”来编写它:

print gini [-> houses ]

然后 gini 可能看起来像这样:

to-report gini [ sample-expression ]
  let samples sort [ run-result sample-expression ] of turtles
  ;;; ... the rest of your gini function here
  report G
end

好的,但是您在函数中嵌入了“of turtles”。但是,如果稍后您想针对某些子群体评估此函数,或者可能使用补丁而不是海龟怎么办?

您也可以通过将代理集作为输入来解决这个问题。

to-report gini [ anon-reporter source ]
  let samples [ run-result anon-reporter ] of source
  ;; etc
end

然后写:

print gini [-> measure-1 ] turtles
print gini [-> measure-2 ] turtles
print gini [-> measure-3 ] turtles

呃,有点尴尬。让我们添加一点语法糖:

to-report of_ [ agents ] report agents end

现在我们可以写:

print gini [-> measure-1 ] of_ turtles
print gini [-> measure-2 ] of_ turtles
print gini [-> measure-3 ] of_ turtles

哦,亲爱的。这看起来很眼熟,不是吗?但是比我们开始时更冗长。

所以现在我们回到:

print gini [ measure-1 ] of turtles