Skip to content

Instantly share code, notes, and snippets.

@aviatesk
Last active May 4, 2020 12:21
Show Gist options
  • Save aviatesk/e855b3168231b744f11ac43f25a7eb34 to your computer and use it in GitHub Desktop.
Save aviatesk/e855b3168231b744f11ac43f25a7eb34 to your computer and use it in GitHub Desktop.
`@collect` and `@generator` macro -- might be useful in competitive programming, etc...
using MacroTools
function decompose_forblk(forblk)
spec, body = forblk.args
i, itr = spec.args
return i, itr, body
end
"""
@collect ex
Converts the outermost `for` block in `ex` into the corresponding list comprehension expressions.
## Example
```julia
julia> function cumsum′(itr::AbstractVector{T}) where {T<:Number}
s::T = zero(T)
return @collect for i in itr
s += i
end
end
cumsum′ (generic function with 1 method)
julia> @assert cumsum(1:1000) == cumsum′(1:1000)
```
"""
macro collect(ex)
done = false
return MacroTools.prewalk(ex) do x
(done || !Meta.isexpr(x, :for)) && return x
done = true
i, itr, body = decompose_forblk(x)
return :([$(body) for $(i) in $(itr)])
end |> esc
end
"""
@generator ex
Converts the outermost `for` block in `ex` into the corresponding generator expressions.
## Example
```julia
julia> @generator for i in 1:10; i; end .|> print;
12345678910
```
"""
macro generator(ex)
done = false
return MacroTools.postwalk(ex) do x
(done || !Meta.isexpr(x, :for)) && return x
done = true
i, itr, body = decompose_forblk(x)
return :(($(body) for $(i) in $(itr)))
end |> esc
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment