Skip to content

Instantly share code, notes, and snippets.

@jwscook
Last active July 7, 2020 08:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jwscook/ab17ae4298b64aad44a338c444d3d153 to your computer and use it in GitHub Desktop.
Save jwscook/ab17ae4298b64aad44a338c444d3d153 to your computer and use it in GitHub Desktop.
@replacerand macro to replace calls to rand() by a given function e.g. x->0.5
"""
A macro `@replacerand` that replaces the value returned by a call to `rand` with something else.
"""
using Cassette
Cassette.@context ReplaceRand
Cassette.overdub(ctx::ReplaceRand, fn::typeof(rand), args...) = ctx.metadata(args...)
replacerand(f, replacement=(x...) -> 0.5) = Cassette.overdub(ReplaceRand(metadata=replacement), f)
macro replacerand(replacement, ex)
:(replacerand(() -> $(esc(ex)), $(esc(replacement))))
end
# define what rand should be replaced by
replacement() = 0.5
replacement(n) = zeros(n) .+ 0.5
replacement(_, n) = zeros(n) .+ 0.5
@replacerand replacement rand()
function foo()
return rand()
end
@replacerand replacement foo()
module Bar
baz() = rand()
end
using .Bar
@replacerand replacement Bar.baz()
@replacerand replacement rand(2)
@replacerand replacement rand((2, 3))
using Random
rng = Random.MersenneTwister()
@replacerand replacement rand(rng, 2)
@replacerand replacement rand(rng, (2, 3))
@femtomc
Copy link

femtomc commented Jul 6, 2020

Here's a simple way to do this:

using Cassette
Cassette.@context ReplaceRand
Cassette.overdub(::ReplaceRand, fn::typeof(rand), args...) = 0.5

then you can call whatever code you want

ctx = ReplaceRand()
Cassette.overdub(ctx, some_fn, args...)

If you want to customize the value, the metadata can be just a Float64

using Cassette
Cassette.@context ReplaceRand
Cassette.overdub(ctx::ReplaceRand, fn::typeof(rand), args...) = ctx.metadata

with

ctx = ReplaceRand(metadata = 0.9)
Cassette.overdub(ctx, some_fn, args...)

After you declare the context, you have to instantiate it and pass your instance into overdub. The metadata field can be anything you want, it doesn't have to be declared as a struct (unless you want it to be).

@jwscook
Copy link
Author

jwscook commented Jul 6, 2020

Brilliant - thanks very much @femtomc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment