<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<p>Hi,</p>
<p>I'm working on a probabilistic programming language with Haskell
syntax [1]. I am trying to figure out how to intermingle lazy and
strict monadic code without requiring ugly-looking markers on the
lazy code. Does anybody have insights on this?</p>
<p>1. I'm taking a monadic approach that is similar to [2], but I'm
using a lazy interpreter. This allows code such as the following,
which would not terminate under a strict interpreter:<br>
</p>
<pre>run_lazy $ do
xs <- sequence $ repeat $ normal 0 1
return $ take 10 xs
</pre>
<p>Here "xs" is an infinite list of Normal(0,1) random variables, of
which only 10 are returned. In a strict interpreter the line for
"xs" never completes. But in a lazy interpreter, it works fine.</p>
<p>2. However, a lazy interpreter causes problems when trying to
introduce *observation* statements (aka conditioning statements)
into the monad [3]. For example,<br>
</p>
<pre>run_lazy $ do
x <- normal 0 1
y <- normal x 1
z <- normal y 1
2.0 `observe_from` normal z 1
return y
</pre>
<p> In the above code fragment, y will be forced because it is
returned, and y will force x. However, the "observe_from"
statement will never be forced, because it does not produce a
result that is demanded. <br>
</p>
<p>3. My current approach is to use TWO monads -- one for random
sampling (Sample a), and one for observations (Observe a). The
random sampling monad can be lazy, because for random samples
there is no need to force a sampling event if the result is never
used. The observation monad is strict, because all the
observations must be forced.</p>
<p>So this WORKS fine. However... the code looks ugly :-( Help?</p>
<p>4a. One idea is to nest the lazy code within the strict monad,
using some kind of tag "sample :: Sample a -> Observe a". Then
we could write something in the (Observe a) monad like:<br>
</p>
<pre>run_strict $ do
w <- sample $ sequence $ repeat $ normal 0 1
x <- sample $ normal 0 1
2.0 `observe_from` normal x 1
y <- sample $ normal x 1
z <- sample $ normal y 1
2.0 `observe_from` normal z 1
return y</pre>
<p>When the "run_strict" interpreter encounters a statement of the
form (sample $ _ ), it switches to the "run_lazy" interpreter for
that statement.<br>
</p>
<p>In this case, the `observe_from` statement IS forced because it
is in the strict (Observe a) monad. Maybe somewhat surprisingly
w, x, y, and z are forced (ugh!) -- by the outer strict
interpreter, not the inner lazy interpreter. However, the internal
components of w are NOT forced, so the program is able to
terminate.</p>
<p>QUESTION: Is there some way of doing this without manually
writing "sample" in front of all the sampling operations?</p>
<p>QUESTION: is there a way of doing this where the "sample $ _"
lines do NOT have their result forced?<br>
</p>
<p>4b. In order to write "sample" less, it is possible to factor the
sampling code into a separate function (here called "prior"):<br>
</p>
<pre>prior :: Sample ([Double], Double, Double, Double)
prior = do
w <- sequence $ repeat $ normal 0 1
x <- normal 0 1
y <- normal x 1
z <- normal y 1
return (w,x,y,z)
model :: Observe Double
model = do
(w,x,y,z) <- sample $ prior
2.0 `observe_from` normal x 1
2.0 `observe_from` normal z 1
return y
</pre>
<p>This does mean that you have to write "sample" only once... but
it (i) splits the function in half and (ii) forces you to
explicitly pass (w,x,y,z) between the two functions. That
obfuscates the code for no benefit.<br>
</p>
<p>Interestingly, the logical conclusion of this movement of code
from (Observe a) to (Sample a) is to move EVERYTHING to the Sample
monad:</p>
<pre>prior :: Sample (Observe (), Double)
prior = do
w <- sequence $ repeat $ normal 0 1
x <- normal 0 1
let observations1 = [2.0 `observe_from` normal x 1]
y <- normal x 1
z <- normal y 1
let observations2 = [2.0 `observe_from` normal z 1]++observations1
return (observations2,y)
model :: Observe Double
model = do
(observations, y) <- sample $ prior
sequence_ observations
return y</pre>
<p>Now, we have moved all the observations into the (Sample a)
monad, but using horrible syntax! Ugh :-( Also, now the function
"model" is basically the same for all models -- the entire model
has been moved into the prior.<br>
</p>
<p>QUESTION: is there some way to write a monadic function like
"prior" while accumulating things observations in a list?</p>
<p>Thanks for any insights!<br>
</p>
<p>-BenRI<br>
</p>
<p>[1] <a class="moz-txt-link-freetext" href="http://bali-phy.org/models.php">http://bali-phy.org/models.php</a><br>
</p>
<p>[2] Practical probabilistic programming with monads, <a
class="moz-txt-link-freetext"
href="https://dl.acm.org/doi/10.1145/2804302.2804317">https://dl.acm.org/doi/10.1145/2804302.2804317</a></p>
<p>[3] <a class="moz-txt-link-freetext" href="https://github.com/tweag/monad-bayes/issues/32">https://github.com/tweag/monad-bayes/issues/32</a><br>
</p>
</body>
</html>