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?

1 Like

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))
3 Likes

Yes! That works! Thanks!