Attempting to trick NetLogo into executing a function passed as an argument

会有一股神秘感。 提交于 2021-02-10 14:50:21

问题


The following produces a compilation error.

to-report call-first/last [first/last a-list]
  report first/last a-list
end

a-list in the body is highlighted with the error: Expected command.

So I tried the following.

to-report call-first/last [first/last a-list]
  report first map first/last (list a-list)
end

This code compiled(!), but when I attempted to have the observer execute it

call-first/last first [1 2 3]

call-first/last was highlighted with the error message: CALL-FIRST/LAST expected 2 inputs.

Any thoughts about an alternative approach?

Thanks.

P.S. The bigger picture is to find a way (if there is one) to write a higher-order function in NetLogo.

UPDATE:

Asking the observer to execute the following works properly!

call-first-last [[a-list] -> first a-list] [1 2 3] ;; => 1

call-first-last [[a-list] -> last a-list] [1 2 3] ;; => 3

But it sure is a long way around!

Another UPDATE:

Tried

to-report call-first-last [first-last a-list]
  report first map (runresult first-last) (list a-list)
end

This compiled.

But asking the observer to run call-first-last "first" [1 2 3] produced a Runtime Error: FIRST expected 1 input

So the question seems to come down to whether there is a way (other than using an anonymous expression as above) to write an expression that returns a function?


回答1:


I'm not sure I have all the details correct, but my first thought when I saw what you were trying to do is to use runresult. This works:

to-report call-first-last [first-last a-list]
  report runresult word first-last a-list
end

With (for example): call-first-last "last" [1 2 3]

You would need to add some brackets for both word and runresult as you do more complicated expressions with more than two terms.




回答2:


So the question seems to come down to whether there is a way (other than using an anonymous expression as above) to write an expression that returns a function?

And the answer comes down to... no.

When you tried writing call-first/last first [1 2 3], you were trying to use the "concise syntax" for passing procedures to higher-order procedures: passing the name of the procedure directly instead of passing an expression like [ xs -> first xs ]. (You can read a bit about it in the programming guide.)

This syntax works with built-in NetLogo primitives like map and foreach, but not for user-defined procedures. Without getting too formal, the reason for this is that NetLogo primitives' arguments are typed: NetLogo knows that the map expects a reporter as its first argument, so it can parse a call like map first my-list-of-lists correctly. User-written code is not like that: NetLogo has know idea what the type of the first/last argument of your call-first/last procedure is supposed to be.

The standard way to deal with this is to bite the bullet and just write something like call-first-last [xs -> first xs] [1 2 3].

If that really bothers you, you can use Jen's solution (though it would be a bit slower).

You could also write an extension. NetLogo extensions allow you to write primitives that behave like native NetLogo procedures, and thus support the concise syntax. It might be worth it if you have a whole set of procedures like this, but otherwise, that's a whole lot of trouble just to save a few characters.

(Side note: it's up to you, of course, but I would avoid using / in NetLogo variable names. The language allows it, yes, but for pretty much anyone looking at your code, it looks a heck of a lot like a division...)



来源:https://stackoverflow.com/questions/62522535/attempting-to-trick-netlogo-into-executing-a-function-passed-as-an-argument

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!