Thanks. See comments inline. I'm also forwarding to our dev list.
> On Jan 23, 2016, at 5:25 AM, Rasmus Arnling Bååth <
rasmus...@gmail.com> wrote:
>
> Hi Bob,
>
> "Nobody's minor --- please jump in if you have something to say." Yes, I'm guilty of lurking on the Stan dev list, and here are some of my thought on the proposed syntax changes to Stan. At this point in the e-mail I'm 100% fine with that you stop reading and don't even reply, as I'm 101% aware that I have no right to an opinion in this matter at all.
The only reason we're not opening this wider is that it's
a classic bike-shed issue where everyone's going to have
a strong opinion and I just don't have the patience to sort
through it all.
I appreciate thoughtful comments like these.
> I just did a tutorial to Stan for people with an R and/or python background, and when you try to explain the syntax of a new language you try to piggyback on the programming languages people already know, so the below is written from the perspective of me having to explain the new syntax to R/python people.
Ever tried to explain R to Python people or vice-versa?
> Normalization and link functions
> ---------------------------
>
> People coming from Python and (especially) R are really used to add named options to function calls, so it would be very easy to explain that you can just add named options to distribution functions like:
>
> poisson(alpha, link=log, norm=true)
>
> where, if you leave the options out, they have sensible defaults (say link=identity, norm=false)
I think part of the divide is that R and Python are primarily
scripting languages. As such, their functions often look like
command line calls --- functions bristling with dozens if not
hundreds of configuration options. In that situation, you pretty
much need named arguments.
I want to keep things more like C in Stan, where the functions
are themselves simple. In that situation, it makes much more sense
not to name them.
> If the syntax was poisson<link=log, norm=true>(alpha) then you would have to explain that some function arguments go in the parentheses() but some go into the tag<>. If what goes into the tag is more a way selecting what function to run, rather than being arguments to the function, then it's almost like the tag is part of the function name, which is completely cool.
That's exactly why that was suggested. It's how templates
work in C++ --- they're not arguments, they literally choose
different functions (which can be super super confusing in
C++).
> But then there are almost three "levels" for giving "options" to functions: ()-arguments, <>-arguments and suffixes and you would have to give people a mental model for what goes where. Here are the extreme version of these three levels:
>
> poisson_loglink_lpdf_norm(alpha)
> poisson(alpha, link=log, norm=true, log=true)
> poisson<link=log, norm=true, log=true>(alpha)
>
> To me it's not directly obvious which arguments/options should be suffixes, ()-arguments, or <>-arguments.
The only ()-argument as you're calling it is alpha here.
At least if we want to fit into Stan's current type system
neatly.
Stan doesn't have built-in boolean types (though we use
0 for false and non-zero for true as many languages do).
The clearcut case is link=log --- there's no value here,
it's more like an enum.
> Vertical Bar Notation
> --------------
>
> I think it's great if Stan's syntax look more like probability-notation, but personally I feel like more confused about the bar notation than the tilde notation (which is going away). When introducing Stan I can imagine questions like:
>
> "So the data goes to the left of the bar?"
>
> "Which is not the case, often you have parameters to the left of the bar, and you can even imagine having data to the right of the bar."
This isn't a Stan problem so much as a teaching of statistics
question. What source can you give them for anything that
doesn't use the bar notation?
> "So what does the bar mean?"
>
> "Well, sometimes Stan uses comma to separate arguments and sometimes a bar , it's just something you have to memorize."
I realize this is just a dramatization for expository purposes,
but I think that'd be a terrible answer.
The right answer is whatever you'd say when someone asks
you "why does normal(y | mu, sigma) get written with a bar
in stats textbooks"? And for extra credit, "why is it
sometimes written with a semicolon?". (Just want to see if
Andrew's paying attention.)
> If I understood it right, what is left of the bar integrates to 1.0,
Right (or sums to one for a pmf).
> but then if the default is for pdfs to be non-normalized, then that wont be the case anyway, right?
But it will be true up to a constant --- the normalizing constant
we drop.
Personally, I'm ambivalent about the bar. What I don't
want is to allow things to be written multiple ways, because
I don't want dialects to develop.
> Increment Log Density Statement
> --------------
>
> At my tutorial there was one or two people that got into trouble because they though y ~ normal(m, s) meant y is sampled from a Normal distribution, but I just told them that ~ is just syntactic sugar and that there is no sampling going on, and they bought that.
In case it was a hard sell before they bought it,
you can always show them the C++ code that gets compiled.
> If you have to write out the following instead:
>
> target += normal_lpdf(y | m, s);
>
> then you really force people to understand how Stan works. However, if you already understan how Stan works then y ~ normal(m, s) is unambiguous (and just a beautiful syntax in my eyes :), and if you don't know how Stan works then target += normal_lpdf(y | m, s); is not going to make much sense anyway.
This has been my main concern all along. But pretty much
every other developer on the project is against me on this one.
> The pros of using "y ~ *" rather than "target += *_lpdf(y |" is also that it's more DRY (don't repeat yourself).
I think you're right here. The question is always whether
the repetition's worth it.
The nice part about it will be consistency --- instead of
having the ~ and the increment_log_prob(), we'd only have
have "target +="
Maybe. I never bought (language is a virus!) from Python
that you don't need indentation and brackets. But you're
> Final thoughts
> ---------------------
>
> * If the vertical bar is introduced, then perhaps a comma could still be used, but just result in a informative warning instead of a syntax error? I just see myself forgetting where the bar goes all the time...
> * If the "magic" tilde syntax is dropped, would it be so bad to keep it as a syntactic sugar macro that just directly mapped
>
> y ~ normal(mu, sigma)
>
> to
>
> target += normal_lpdf(y | mu, sigma);
>
> without any other magic happening. If this macro rule was described just once in big red letters in the manual, then it should be impossible to miss! :)
The plan's to deprecate it, but it might not be a bad
idea to keep it.
> Again, I just want to say that I'm aware that I have no business having an opinion in this matter at all and that I don't expect any reply. (I just have been thinking about Stan syntax a lot...) And if this mail has annoyed you I wish to apologize!
Not at all. Thanks for sharing.
It's a difficult set of tradeoffs we're wrestling with or this
would've been done.
Honestly, had it been up to me, I was only planning on replacing
increment_log_prob(u);
with
target += u;
which I think is an improvement there.
- Bob