|
13 | 13 | return element, (val, new_state) |
14 | 14 | end |
15 | 15 |
|
| 16 | +""" |
| 17 | + @thunk expr |
| 18 | +
|
| 19 | +Define a [`Thunk`](@ref) wrapping the `expr`, to lazily defer its evaluation. |
| 20 | +""" |
| 21 | +macro thunk(body) |
| 22 | + # Basically `:(Thunk(() -> $(esc(body))))` but use the location where it is defined. |
| 23 | + # so we get useful stack traces if it errors. |
| 24 | + func = Expr(:->, Expr(:tuple), Expr(:block, __source__, body)) |
| 25 | + return :(Thunk($(esc(func)))) |
| 26 | +end |
| 27 | + |
| 28 | +""" |
| 29 | + unthunk(x) |
| 30 | +
|
| 31 | +On `AbstractThunk`s this removes 1 layer of thunking. |
| 32 | +On any other type, it is the identity operation. |
| 33 | +
|
| 34 | +In contrast to [`extern`](@ref) this is nonrecursive. |
| 35 | +""" |
| 36 | +@inline unthunk(x) = x |
| 37 | + |
| 38 | +@inline extern(x::AbstractThunk) = extern(unthunk(x)) |
| 39 | + |
| 40 | +Base.conj(x::AbstractThunk) = @thunk(conj(unthunk(x))) |
| 41 | +Base.adjoint(x::AbstractThunk) = @thunk(adjoint(unthunk(x))) |
| 42 | +Base.transpose(x::AbstractThunk) = @thunk(transpose(unthunk(x))) |
| 43 | + |
16 | 44 | ##### |
17 | 45 | ##### `Thunk` |
18 | 46 | ##### |
@@ -59,42 +87,14 @@ Also if we did `Zero() * res[1]` then the result would be `Zero()` and `f(x)` wo |
59 | 87 | with a field for each variable used in the expression, and call overloaded. |
60 | 88 |
|
61 | 89 | Do not use `@thunk` if this would be equal or more work than actually evaluating the expression itself. |
| 90 | +This is commonly the case for scalar operators. |
62 | 91 |
|
63 | 92 | For more details see the manual section [on using thunks effectively](http://www.juliadiff.org/ChainRulesCore.jl/dev/writing_good_rules.html#Use-Thunks-appropriately-1) |
64 | 93 | """ |
65 | 94 | struct Thunk{F} <: AbstractThunk |
66 | 95 | f::F |
67 | 96 | end |
68 | 97 |
|
69 | | - |
70 | | -""" |
71 | | - @thunk expr |
72 | | -
|
73 | | -Define a [`Thunk`](@ref) wrapping the `expr`, to lazily defer its evaluation. |
74 | | -""" |
75 | | -macro thunk(body) |
76 | | - # Basically `:(Thunk(() -> $(esc(body))))` but use the location where it is defined. |
77 | | - # so we get useful stack traces if it errors. |
78 | | - func = Expr(:->, Expr(:tuple), Expr(:block, __source__, body)) |
79 | | - return :(Thunk($(esc(func)))) |
80 | | -end |
81 | | - |
82 | | -""" |
83 | | - unthunk(x) |
84 | | -
|
85 | | -On `AbstractThunk`s this removes 1 layer of thunking. |
86 | | -On any other type, it is the identity operation. |
87 | | -
|
88 | | -In contrast to [`extern`](@ref) this is nonrecursive. |
89 | | -""" |
90 | | -@inline unthunk(x) = x |
91 | | - |
92 | | -@inline extern(x::AbstractThunk) = extern(unthunk(x)) |
93 | | - |
94 | | -# have to define this here after `@thunk` and `Thunk` is defined |
95 | | -Base.conj(x::AbstractThunk) = @thunk(conj(unthunk(x))) |
96 | | - |
97 | | - |
98 | 98 | (x::Thunk)() = x.f() |
99 | 99 | @inline unthunk(x::Thunk) = x() |
100 | 100 |
|
|
0 commit comments