This is probably not a great example of recursion but suppose I have a recursive function, usually in a loop I can break out of the first layer with something simple like
function check(stuff)
cont = Ref(true)
@async for i = stuff
cont[]||break
iseven(i) ? println(i) : sleep(8)
end
return cont
end
julia> v = [1,2,3,4,1,2,3,4]
8-element Vector{Int64}:
1
2
3
4
1
2
3
4
julia> test = check(v)
Base.RefValue{Bool}(true)
julia> 2
julia> test[]=false
false
but if the function contains a recursive loop
function reccheck(stuff)
cont = Ref(true)
@async for i = stuff
cont[]||break
iseven(i) ? println(i) : reccheck(filter!(x-> x!=i,stuff))
sleep(8)
end
return cont
end
then the inner loops are no longer stopped by the initial cont [] || break
. Just wondering if there was a simple workaround for this? Thanks!
I think it has not much to do with recursion, but rather that you should pass forward the reference to the nestled instances, e.g.
function reccheck(stuff, cont = Ref(true) )
@async for i = stuff
cont[] || break
iseven(i) ? println(i) : reccheck( filter!(x-> x!=i,stuff), cont)
sleep(8)
end
return cont
end
1 Like
Wow this is super helpful thanks so much! I had no idea this could be done. Could you confirm the following few points to see if my understanding of this process is correct? (Sorry I am still trying to understand on how Ref
objects work). According to the docs a Ref object is loaded with []
. So if
Instance = recheck(stuff, cont)
-
By setting Instance[] = false
we are loading the reference object in the instance and setting it to false
. This in turn trips the cont[] || break
circuit. Does this mean Instance[] === cont[]
? If cont
is only returned after the loop is completed how is Instance
reassigning cont
prior to the completion of the loop?
-
The exclusive or circuit in the function had to be cont[] || break
and NOT cont || break
because without the []
call the reference object would not be loaded?
-
If there were more than one reference object being returned by the function would the appropriate way to load with separate values be via tuple? e.g.
function reccheck2(stuff, cont = Ref(true), rep = Ref(true))
# some function
return (; cont, rep)
end
Instance2 = recheck2(stuff)
Instance2[1][] = false
Instance2[2][] = true
I understand if you’re busy and don’t have time for the follow ups, either way thanks so much for the solution!
Hi, I think all your points seems correct.
-
Since you use @async, cont
will be returned before the loop ended it’s computation.
If you remove the @async
all of that would not work anymore.
-
Yes.
-
Your approach works.
Another common design is, to ask the user to create the Ref
objects and pass them when calling the function. That way one can use the return for actually meaningfull things.
Just some example, maybe it doesn’t run but to show the idea Here the user can decide if they want to pass a reference or not, and only the outer execution is async:
function reccheck2(stuff; cont = Ref(true), rep = Ref(true))
j = 0
for i = stuff
cont[]||break
iseven(i) ? println(i) : reccheck(filter!(x-> x!=i,stuff), cont = rep, rep = rep)
sleep(8)
j += 1
end
return j
end
rep = Ref(true)
@async result = revcheck( 1:8; rep = rep )
rep[] = false
1 Like
ahh…got it. Thanks so much!