Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: support referring to variables from outer tasks #351

Closed
SethTisue opened this issue May 16, 2013 · 10 comments
Closed

feature: support referring to variables from outer tasks #351

SethTisue opened this issue May 16, 2013 · 10 comments

Comments

@SethTisue
Copy link
Collaborator

?, ?1, ?2 etc always refer to the innermost enclosing task, so you can't access the inputs of an outer task.

In a command task, you can work around it use let in the outer task to give the task input a name. But it's awkward. And in the reporter case there's no reporter equivalent of let, so with reporter tasks, you get stuck.

This is the biggest missing feature in tasks. (@joshcough and I were well aware of it all along. We just didn't have time to do anything about it for 5.0.)

consider e.g. this program:

to-report tabulate [counts values]
  report reduce sentence (map ditto counts values)
end

to-report ditto [n value]
  report n-values n [value]
end

currently it's impossible to write this in one procedure. if you try:

to-report tabulate [counts values]
  report reduce sentence (map [n-values ?1 [?2]] counts values)
end

it doesn't work because the ?2 in the body of the n-values refers to the nonexistent second input to the n-values task, rather than the intended meaning where ?2 refers to the second input to the enclosing map task. (and trying to do let ditto task ... first doesn't help.)

attempting to write the Y combinator in NetLogo runs afoul of the same issue.

also, Uri received this feature request:

 > Make tasks more general so that tasks can take tasks as input and 
 > produce tasks as output. This would involved control over the task 
 > variables. 

and he confirms that it refers to this issue.

so, we have a hole in the language.

there are several possible ways we could address it. in increasing order of how difficult they would be to implement:

the easiest way would be to add letreport to the language:

to-report tabulate [counts values]
  let ditto task [ letreport x ?2 n-values ?1 [x] ]
  report reduce sentence (map ditto counts values)
end

here the use of let is just for clarity; cramming it all into one command would work too

@ToonTalk has said: "To use let inside a reporter is something I often want. If possible would be nice if it was also called 'let' rather than 'letreport' but maybe that's not feasible."

the next easiest way would be to add some kind of syntax for giving names to task inputs, instead of just numbers. something like let ditto task [n x => n-values n [x]]

the hardest way would be to support commands inside the bodies of reporter tasks, something like:

let ditto task [ let x ?2 report n-values ?1 [x] ]
@SethTisue
Copy link
Collaborator Author

another use case: suppose I want a list of 5 reporter tasks: the first one reports 0, the second reports 1, and so on. an attempt is n-values 5 [task ?] but it doesn't work; you get 5 single-input identity tasks instead. if we could name task inputs, then it would be n-values 5 [n => task n]

@SethTisue
Copy link
Collaborator Author

The Berkeley Logo syntax is [[x] x * x]

@SethTisue
Copy link
Collaborator Author

Sometimes the lack of named task inputs doesn't mean something is inexpressible, merely awkward/verbose. Take e.g. Travis's code at http://groups.yahoo.com/group/netlogo-users/message/16997 :

(foreach lower-bound upper-bound [
let temp-lower ?1
let temp-upper ?2
print filter [? > temp-lower and ? <= temp-upper] source-list
])

Since the outer loop is a foreach, we can use let to name the inputs (we don't need letreport). But it's verbose; it would be nicer to be able to name the inputs directly.

@SethTisue
Copy link
Collaborator Author

it should probably be forbidden for task input names to shadow other identifiers, since we forbid shadowing everywhere else in the language

@SethTisue
Copy link
Collaborator Author

Internally, our looping constructs currently mutate a single binding rather than establish a fresh binding for each iteration of the loop. Currently that fact is invisible to users since you can't close over a task input. But once we have named inputs, you should be able to close over them, so we'll need to make sure you're always closing over a fresh binding.

Some languages make the opposite choice (exposing the mutable binding to be closed over), but these languages are to be derided and shunned for it, and we should not join their ranks.

@mrerrormessage
Copy link
Contributor

Fixed in hexy with the addition of ->-anonymous procedures.

@SethTisue
Copy link
Collaborator Author

we'll need to make sure you're always closing over a fresh binding

@mrerrormessage did this happen?

@mrerrormessage
Copy link
Contributor

mrerrormessage commented Aug 30, 2016

@SethTisue , that didn't happen.

Just to confirm, we're talking about the behavior displayed in the following language test:

globals [glob1 lambdas]
O> set lambdas [] repeat 5 [ let bar 0 set lambdas lput [ [] -> set bar bar + 1 set glob1 bar ] lambdas ]
O> foreach lambdas [ [l] -> run l ]
; with fresh bindings
glob1 => 1
; without fresh bindings
glob1 => 5

This test currently reports the second case (5). I'll see what I can do to fix this. Just as a note, while I was trying to construct this I found it was even more awkward than I expected in NetLogo since you can't introduce a let in a reporter lambda.

But the example above actually is possible in NetLogo 5 using tasks, so this sounds like an actual semantic change, albeit a very minor one. Can you clarify whether that's what you mean?

As another option:

globals [glob1 lambdas]
O> set lambdas [] repeat 5 [ let bar 0 set lambdas lput (runresult [ [bar'] -> [ [] -> set glob1 bar' + 1 ] ] bar) lambdas set bar 4 ]
O> foreach lambdas [ [l] -> run l ]
glob1 => 1

This test passes. I should also note that it isn't symmetric with the first test as it isn't possible to set a lambda variable, which in itself may remove the possibility for this to become an issue.

@SethTisue
Copy link
Collaborator Author

Just to confirm, we're talking about the behavior displayed in the following language test

yes

and reporter tasks too, so e.g. print map runresult n-values 5 [[x] -> [[] -> x]] should be [0 1 2 3 4] (and is in hexy when I tried it just now, but I suggest making sure that fact is covered by tests)

the example above actually is possible in NetLogo 5 using tasks

ha. well, that's a bug in NetLogo 5. not a known bug afaicr. good catch!

@SethTisue
Copy link
Collaborator Author

it was even more awkward than I expected in NetLogo since you can't introduce a let in a reporter lambda

yes, this is covered already here on this ticket, see above about letreport

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants