NetLogo 5到6转换:用于循环

NetLogo 5到6转换:用于循环,netlogo,Netlogo,我是NetLogo的新手,正在尝试将NetLogo 5.3.1中内置的模型转换为NetLogo 6.0.3。自动转换器不工作,因此我尝试手动将任务转换为匿名过程。但是,我仍停留在NL-5.3.1代码以下部分的转换上: let tempNewList [ ] ; to store the new list (foreach n-values (highest-family-id + 1) [?] [

我是NetLogo的新手,正在尝试将NetLogo 5.3.1中内置的模型转换为NetLogo 6.0.3。自动转换器不工作,因此我尝试手动将任务转换为匿名过程。但是,我仍停留在NL-5.3.1代码以下部分的转换上:

let tempNewList [ ]                                           ; to store the new list
  (foreach n-values (highest-family-id + 1) [?] [             ; search through all family-ids ever created in model
      if count turtles with [family-id = ?] >= 2 [            ; if family-id belongs to 2 or more turtles... 
        set tempNewList lput ? tempNewList                    ; ...  add to list
      ]
  ])
  set families tempNewList
在这里,目标是更新“families”全局变量,该变量是至少2个人持有的家族ID列表。当在NL-6.3.0中打开时,此代码会如预期的那样给出错误:“未定义”

我将“”重命名为eachFamilyID,并对匿名过程使用了新的“->”语法。例如,我尝试将上述代码更改为:

let tempNewList [ ]                                                       
  (foreach n-values (highest-family-id + 1) [ eachFamilyID ->  
    if count turtles with [family-id = eachFamilyID] >= 2 
    [set tempNewList lput eachFamilyID tempNewList ]  ]                
    ])
set families tempNewList
这会产生错误:“N-VALUES期望此输入是匿名报告程序,但得到的却是匿名命令”

在读了很多书,用谷歌搜索了很多遍之后,我仍然不知道该怎么做。有什么建议吗


操作系统:MacOS High Sierra 10.13.4版

您正面临一个简单的语法问题,但我也认为可能值得退一步,重新思考解决问题的方法。让我们从语法开始

如果查看未转换的代码,您会注意到顶级结构如下所示:

(foreach n-values (highest-family-id + 1) [?] [ ... ])
let all-ids remove-duplicates [ family-id ] of turtles
这里使用了两个主要的原语,
foreach
n-values
,它们都接受一个任务参数

foreach
的情况下,该任务就是整个
[如果计数海龟…]
块,我在这里省略了
[…]

n-values
的情况下,该任务只是标识函数,
[?]
,它只会返回传递给它的任何内容。例如,
n-values 5[?]
将为您提供列表
[0 1 2 3 4]
,因为这些是
n-values
作为
传递给其任务参数的连续值

NetLogo 6中的语法已更改,但仍需要一些方法来生成连续的值。现在看看您的转换版本:

(foreach n-values (highest-family-id + 1) [ eachFamilyID -> ... ])
你能看到少了什么吗?只有一个匿名过程!对
n-values
的调用尝试使用用于
foreach
的匿名命令,该命令解释了您收到的错误消息。要解决此问题,只需在代码中添加NetLogo 6版本的identity函数:

(foreach n-values (highest-family-id + 1) [ n -> n ] [ eachFamilyID -> ... ])
let counts table:counts [ family-id ] of turtles
set families map first filter [ p -> last p >= 2 ] table:to-list counts
这会解决你眼前的问题

现在让我们后退一步。您试图做的是构建一个列表,其中只包含符合特定条件的值。在您的情况下,您希望只保留至少有两个成员的族的族ID。NetLogo有一个内置的原语,它可以做类似的事情:。这里有一种使用它的方法,它与您已经在做的事情比较接近:

let all-ids n-values (highest-family-id + 1) [ n -> n ]
set families filter [ id ->
  count turtles with [ family-id = eachFamilyID ] >= 2
] all-ids
这不是已经更好了吗?然而,它仍然可以改进。首先,NetLogo 6有一个原语,您可以经常使用它来代替
n-values

let all-ids range (highest-family-id + 1)
很好。但你也可以这样做:

(foreach n-values (highest-family-id + 1) [?] [ ... ])
let all-ids remove-duplicates [ family-id ] of turtles
这稍微慢一点,但它仍然保证为您提供所有正在使用的家庭ID,并且您可以避免出现“逐个关闭”错误的可能性

但是,如果您愿意使用
扩展,则可以采用更简洁的方法。它涉及原始人。假设代码顶部有
extensions[table]
,下面是如何使用它的:

(foreach n-values (highest-family-id + 1) [ n -> n ] [ eachFamilyID -> ... ])
let counts table:counts [ family-id ] of turtles
set families map first filter [ p -> last p >= 2 ] table:to-list counts
它看起来有点神秘,但它的优点是比其他方法快得多(一旦你理解了它,就有点优雅)。让我试着把它打开一点

第一行非常简单:它使用
table:counts
来计算每个
家族id
在我们所有的海龟身上出现的次数,这正是我们需要的信息!该信息存储在一个“表”中,该表将“键”与值相关联。在这种情况下,每个族ID都是一个键,其值是它出现的次数

一旦我们有了它,我们所需要做的就是一些过滤,只保留值至少为2的键。表扩展没有用于筛选表的原语,但我们可以使用
table:to list
,轻松地将表转换为列表,然后筛选该列表

table:to list
的结果是一个列表列表,其中每个子列表有两个元素,对应于原始表中的键值对。假设我们只有两个家庭,家庭1有5个成员,家庭2只有1个成员。我们将得到以下列表:
[[1 5][2 1]]
。很简单!现在,如果我们在这个问题上使用
filter
,我们只需要保留子列表,其中第二个成员(即
最后一个
成员)是
=2
。这是上面代码的
过滤器[p->last p>=2]…
部分

过滤完列表后,还有最后一步:我们只需要保留的每个子列表的第一个元素。将列表转换为其他内容(这就是我们在这里要做的)通常是使用原语完成的,原语使用一个报告器,将其应用于列表的每个元素并返回结果列表。在本例中,我们直接将其传递给报告者,但我们也可以使用匿名报告者,如
[p->first p]

然而,如果这是我的模型,我会采取完全不同的方法。使用数字ID是一件痛苦的事情,也是代码中的一大错误源。NetLogo有更好的方法来表示事物之间的关系。我将创造两种不同的海龟品种:
家族
,并在人和他们所属的家族之间建立联系。让至少有两名成员的家庭参加会议只需:

families with [ count my-links >= 2 ]

更清楚了,不是吗?

非常感谢您提供了非常有用的答案!非常感谢。我现在明白了这两个原语都需要一个匿名过程,我只是p