EDIT: I had thought this was a question about Soss (you didn’t specify a PPL in the text), but I just noticed the turing tag. So… maybe nevermind?
Return statements are a coming soon feature. We want to be able to write, for example,
mycauchy() = @model begin
x ~ Normal()
y ~ Normal()
return x/y
end
So rand(mycauchy()) would just return a Float64.
That part is simple enough. But how would we implement logpdf(mycauchy(), c::Float64)? In this case we can figure it out, but there are too many options for a way to do this in general, and they’re all much slower than we’d like.
What we need is a way to pass the internal state as well. And a quick fix won’t really do it, we need the result to be nicely composable. For example, say we have a “slash distribution”,
slash = @model a,b begin
x ~ a
y ~ b
return x/y
end
The arguments to slash might be Distributions, or could themselves for Soss models. We need things to propagate correctly in either case.
I think there will be a lot of advantages to this once we straighten it out, but it will take thinking through it some more to be sure we get it right. I think we’ll take some ideas from Gen on this, but there are some details to work through.
When you define a model and instantiate it, you get a callable object based on the functional form that you wrote for your model:
@model function bla(x)
y ~ Normal()
x ~ Normal(y)
return "hi"
end
m = bla([1,2,3]) # instantiate the model
m() # evaluate the "instance"
In that last m(), the content of the transformed function is run with some extra stuff, and "hi" will be returned.
But you almost never need that. The return value has almost no meaning in a Turing setting – what you are interested in is the trace. Usually, you instead call sample(m, alg, N) instead, which ignores the return value and internally does something akin to
vi = VarInfo()
m(vi)
where vi is written to, and after the call contains, most importantly, the sampled values of the variables, and the accumulated log-probability.
You can use return for early termination, and other hacks, but that’s changes of the operational behaviour, not really of the probabilistic meaning.
We are planing to utilise the return block in Turing.
In the future (once I started working on the PR), the return statement will allow you to specify which variables you want to store in your trace. If you don’t specify it, this will fall back to the current behaviour and if you specify a return statement you will be able to track transformed variables and the compiler will be able to marginalise out parameters if they are not of interest.