Language Overview¶
The WebPPL language begins with a subset of JavaScript, and adds to it primitive distributions and operations to perform sampling, conditioning and inference.
Syntax¶
Following the notation from the Mozilla Parser API,
the language consists of the subset of JavaScript that can be built
from the following syntax elements, each shown with an example
:
Element | Example |
---|---|
Program | A complete program, consisting of a sequence of statements |
BlockStatement | A sequence of statements surrounded by braces, {var x = 1; var y = 2;} |
ExpressionStatement | A statement containing a single expression, 3 + 4; |
ReturnStatement | return 3; |
EmptyStatement | A solitary semicolon, ; |
IfStatement | if (x > 1) { return 1; } else { return 2; } |
VariableDeclaration | var x = 5; |
Identifier | x |
Literal | 3 |
FunctionExpression | function (x) { return x; } |
CallExpression | f(x) |
ConditionalExpression | x ? y : z |
ArrayExpression | [1, 2, 3] |
MemberExpression | Math.log |
BinaryExpression | 3 + 4 |
LogicalExpression | true || false |
UnaryExpression | -5 |
ObjectExpression | {a: 1, b: 2} |
AssignmentExpression | globalStore.a = 1 (Assignment is only supported by the global store.) |
Note that general assignment expressions and looping constructs are
not currently supported (e.g. for
, while
, do
). This is
because a purely functional language is much easier to transform into
Continuation-Passing Style (CPS), which the WebPPL implementation uses to implement inference algorithms such as
enumeration and SMC. While these
restrictions mean that common JavaScript programming patterns aren’t
possible, this subset is still universal, because we allow recursive
and higher-order functions. It encourages a functional style, similar
to Haskell or LISP, that is pretty easy to use (once you get used to
thinking functionally!).
Here is a (very boring) program that uses much of the available syntax:
var foo = function(x) {
var bar = Math.exp(x);
var baz = x === 0 ? [] : [Math.log(bar), foo(x-1)];
return baz;
}
foo(5);
Calling JavaScript Functions¶
JavaScript functions can be called from a WebPPL program, with a few restrictions:
- JavaScript functions must be deterministic and cannot carry state
from one call to another. (That is, the functions must be
‘referentially transparent’: calling
obj.foo(args)
must always return the same value when called with given arguments.) - JavaScript functions can’t be called with a WebPPL function as an argument (that is, they can’t be higher-order).
- JavaScript functions must be invoked as the method of an object (indeed, this is the only use of object method invocation currently possible in WebPPL).
All of the JavaScript functions built into the environment in which WebPPL is running are automatically available for use. Additional functions can be added to the environment through the use of packages.
Note that since JavaScript functions must be called as methods on an
object, it is not possible to call global JavaScript functions such as
parseInt()
directly. Instead, such functions should be called as
methods on the built-in object _top
. e.g. _top.parseInt('0')
.