A question about closures

Hi,

I’m trying to work out how to construct a closure for the following case:

The Agents package has a random_agent(agent, condition) function and I want to call it with a condition closure. I though the following would work:

using Agents

mutable struct MyAgent <: AbstractAgent
    id::Int64
    state::Int64
end

has_state(agent, state) = agent.state == state

model = ABM(MyAgent)
add_agent!(MyAgent(1, 1), model)
add_agent!(MyAgent(2, 1), model)
condition = state -> has_state(agent, state)

random_agent(model, condition(1))

But then I get the following error:

ERROR: UndefVarError: agent not defined
Stacktrace:
 [1] (::var"#7#8")(::Int64) at ./none:1
 [2] top-level scope at none:1

What am I doing wrong?

Thanks in advance,
Stef

You haven’t defined any variable named agent for the closure to capture. What do you expect agent to refer to in your condition closure?

I’m pretty new to working with closures so this was my reasoning:

random_agent() calls condition(agent)
I need to pass the a state to the condition function.
If I use a closure I can pretend the state in the function call.

So my expectation was that

condition(1)

would translate into

condition(agent, state = 1)

where agent would be bound in the random_agent() function.

But apparently that’s not the way it works :slight_smile:

So, how do I make it work?

Thanks in advance,
Stef

function makeCondition(agent) 
  state -> has_state(agent, state)
end
condition = makeCondition(valueToCaptureAsAgentInClosure)

I don’t see how that solves the problem. I don’t know which agent will be passed to the condition() function since the random_agent() function supplies the agent. I need to supply the state.

But maybe I’m missing something.

I tried passing the condition to the random_agent() function as makeCondition(1) but then I get the following error:

ERROR: type Int64 has no field state
Stacktrace:
 [1] getproperty(::Int64, ::Symbol) at ./Base.jl:33
 [2] has_state(::Int64, ::MyAgent) at ./none:1
 [3] (::var"#9#10"{Int64})(::MyAgent) at ./none:2
 [4] random_agent(::AgentBasedModel{Nothing,MyAgent,typeof(fastest),Nothing}, ::var"#9#10"{Int64}) at /Users/stef/.julia/packages/Agents/VKc78/src/core/model.jl:173
 [5] top-level scope at none:1

It sounds like you’d rather have the closure enclose the state, not the agent. Perhaps

condition(state) = agent -> has_state(agent, state)
random_agent(model, condition(1))

Yes! That works! Thanks!