I didn't get WebPPL at first. Or PPLs (Probabilistic Programming Languages) generally.
Nearly every language can pick random numbers:
uniform(0, 1)
And nearly every language can flip coins:
repeat(10, function() { flip(0.3) ? 'Heads' : 'Tails' })
In those ways, WebPPL is like any other language
… but other languages don't have Infer.
Infer(…) returns distributions. How often does a function return this value vs that value.
So Infer can confirm that yes, uniform(0, 1) returns a fairly even distribution of numbers between 0 and 1, and yes, flip(0.3) yields heads about 30% of the time:
viz(Infer({method: 'MCMC', samples: 10000}, function() { return {x: uniform(0, 1)} })) viz(Infer(function() { return flip(0.3) ? 'Heads' : 'Tails' }))
… But it can go backwards, too!
Let's say you wrote a program to generate random ASCII art of a creature-buddy snacking on pellets:
var trail = function(steps, sawPac, pacProb) { if (steps == 0) return '' if (sawPac) return 'o' + trail(steps-1, sawPac, pacProb) if (flip(pacProb)) { return 'ᗧ ' + trail(steps-1, true) } else { return '.' + trail(steps-1, sawPac, pacProb) } } var p = 0.5 print(trail(30, false, p)) print(trail(30, false, p)) print(trail(30, false, p)) print(trail(30, false, p))
And now you're like, "What p do I pick if I want 'em to make it to the other side more often?" Well, let's infer p:
var trail = function(steps, sawPac, pacProb) { if (steps == 0) return '' if (sawPac) return 'o' + trail(steps-1, sawPac, pacProb) if (flip(pacProb)) { return 'ᗧ ' + trail(steps-1, true) } else { return '.' + trail(steps-1, sawPac, pacProb) } } Infer({method: 'MCMC', samples: 10000}, function() { // Pick a random pacProb. var p = uniform(0, 1) // Bail unless we generate a trail with our friend at the far end. condition(trail(30, false, p).slice(28, 30) == 'ᗧ ') return {p: p} })
It looks like values between 0.025 and 0.1 are good?
var trail = function(steps, sawPac, pacProb) { if (steps == 0) return '' if (sawPac) return 'o' + trail(steps-1, sawPac, pacProb) if (flip(pacProb)) { return 'ᗧ ' + trail(steps-1, true) } else { return '.' + trail(steps-1, sawPac, pacProb) } } var p = 0.06 print(trail(30, false, p)) print(trail(30, false, p)) print(trail(30, false, p)) print(trail(30, false, p))
ML achieved.
To be continued…