-
Notifications
You must be signed in to change notification settings - Fork 65
Description
it is not too hard to endup in a situtation where you have say
Thunk(()->Thunk(()->3)) ie., @thunk(@thunk(3))
One example (written in #30 style) is if you have
rrule(::typeof(f), x) = f(x), y->(NO_FIELDS, @thunk(3))
function rrule(::typeof(g), x)
_, inner_pullback = rrule(f, x)
function g_pullback(y)
(NO_FIELDS, @thunk(g_pullback(y)[2])
end
return g(x), g_pullback
end
Especially with #30 where we (by nescity) throw a lot more @thunks around.
This is particularly annoying in test right now, and so probably in real use too.
I see two ways to resolve this:
1. make extern(::Thunk) recursive
this is just changing
@inline extern(x::Thunk) = x.f()
to
@inline extern(x::Thunk) = extern(x.f())
This doesn't help for (Casted(Zero()) or Casted(@thunk(3)) etc
but Casted could have the same change I guess,
or it could just or away #10
2. make all externing recursive
We would change current definitions of extern into
extern1
then change extern to call extern1 until the result is no longer a AbstractDifferential.
(either via recursion, or via a loop)
3. Make `Thunk(()->Thunk
Way harder than it looks.
Similarly does not apply to things other than thunks
Not sure on the implications of these on inlining,
I know inlining hates recursion.
Here is some test code I prepared earlier.
@testset "Thunk" begin
@test extern(Thunk(()->3)) == 3 == extern(@thunk(3))
@test extern(Thunk(()->Thunk(()->3))) == 3 == extern(@thunk(@thunk(3)))
@test @thunk(3) isa Thunk
end
I think the first one is a good place to start.
And will likely PR that and rebase it into #30