Last active
February 5, 2023 12:54
-
-
Save MikeInnes/8299575 to your computer and use it in GitHub Desktop.
Some useful macros for Julia
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Repeat an operation n times, e.g. | |
# @dotimes 100 println("hi") | |
macro dotimes(n, body) | |
quote | |
for i = 1:$(esc(n)) | |
$(esc(body)) | |
end | |
end | |
end | |
# Equivalent to @time @dotimes ... | |
macro dotimed(n, body) | |
:(@time @dotimes $(esc(n)) $(esc(body))) | |
end | |
# Stop Julia from complaining about redifined consts/types - | |
# @defonce type MyType | |
# ... | |
# end | |
# or | |
# @defonce const pi = 3.14 | |
macro defonce(typedef::Expr) | |
if typedef.head == :type | |
name = typedef.args[2] | |
elseif typedef.head == :typealias || typedef.head == :abstract | |
name = typedef.args[1] | |
elseif typedef.head == :const | |
name = typedef.args[1].args[1] | |
else | |
error("@defonce called with $(typedef.head) expression") | |
end | |
typeof(name) == Expr && (name = name.args[1]) # Type hints | |
:(if !isdefined($(Expr(:quote, name))) | |
$(esc(typedef)) | |
end) | |
end | |
# Julia's do-while loop, e.g. | |
# @once_then while x < 0.5 | |
# x = rand() | |
# end | |
macro once_then(expr::Expr) | |
@assert expr.head == :while | |
esc(quote | |
$(expr.args[2]) # body of loop | |
$expr # loop | |
end) | |
end | |
function memoize(f) | |
cache = Dict() | |
(args...) -> haskey(cache, args) ? cache[args] : (cache[args] = f(args...)) | |
end | |
# Evaluate expressions at compile time, e.g. | |
# hard_calculation(n) = (sleep(1); n) | |
# f(x) = x * @preval hard_calculation(2) # takes 1 second | |
# f(2) => 4 # instant | |
macro preval(expr) | |
eval(expr) | |
end | |
# Speed up anonymous functions 10x | |
# @dotimed 10^8 (x -> x^2)(rand()) # 3.9 s | |
# @dotimed 10^8 (@fn x -> x^2)(rand()) # 0.36 s | |
macro fn(expr::Expr) | |
@assert expr.head in (:function, :->) | |
name = gensym() | |
args = expr.args[1] | |
args = typeof(args) == Symbol ? [args] : args.args | |
body = expr.args[2] | |
@eval $name($(args...)) = $body | |
name | |
end | |
# A dictionary whose values defaut to 0. | |
# You can write counter[k] += 1 without | |
# worrying about whether k has been set. | |
@defonce type Counter{K, V} | |
dict::Dict{K, V} | |
end | |
Counter(K::Type = Any, V::Type = Int) = Counter(Dict{K, V}()) | |
getindex{K, V}(c::Counter{K, V}, k::K) = haskey(c.dict, k)? c.dict[k] : zero(V) | |
setindex!{K, V}(c::Counter{K, V}, v::V, k::K) = c.dict[k] = v |
"""
@loop expression
Repeats the `expression` forever. Useful for asynchronous processing with `Channels`.
"""
macro loop(ex)
quote
while true
$(esc(ex))
end
end
end
See https://discourse.julialang.org/t/anoymous-functions-slow-in-sort/13891 for the anon functions. It seems it is the compile time that changes, not runtime. Why's that? Perhaps the anon fund gets compiled 10^8 times in your macro?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Some very cool stuff here