We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[FR] Add tutorial on implementing new effects
Users at PROBPROG 2018 requested a tutorial on high-level Pyro architecture including advanced features like poutines.  This issue proposes adding a tutorial on implementing a new effect handler.

Whereas #1553 should aim to explain Pyro's architecture in a simplified way, this tutorial should prepare developers to make changes to Pyro.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pyro/poutine/runtime.py`
Content:
```
1 import functools
2 
3 from pyro.params.param_store import _MODULE_NAMESPACE_DIVIDER, ParamStoreDict  # noqa: F401
4 
5 # the global pyro stack
6 _PYRO_STACK = []
7 
8 # the global ParamStore
9 _PYRO_PARAM_STORE = ParamStoreDict()
10 
11 
12 class _DimAllocator(object):
13     """
14     Dimension allocator for internal use by :class:`plate`.
15     There is a single global instance.
16 
17     Note that dimensions are indexed from the right, e.g. -1, -2.
18     """
19     def __init__(self):
20         self._stack = []  # in reverse orientation of log_prob.shape
21 
22     def allocate(self, name, dim):
23         """
24         Allocate a dimension to an :class:`plate` with given name.
25         Dim should be either None for automatic allocation or a negative
26         integer for manual allocation.
27         """
28         if name in self._stack:
29             raise ValueError('duplicate plate "{}"'.format(name))
30         if dim is None:
31             # Automatically designate the rightmost available dim for allocation.
32             dim = -1
33             while -dim <= len(self._stack) and self._stack[-1 - dim] is not None:
34                 dim -= 1
35         elif dim >= 0:
36             raise ValueError('Expected dim < 0 to index from the right, actual {}'.format(dim))
37 
38         # Allocate the requested dimension.
39         while dim < -len(self._stack):
40             self._stack.append(None)
41         if self._stack[-1 - dim] is not None:
42             raise ValueError('\n'.join([
43                 'at plates "{}" and "{}", collide at dim={}'.format(name, self._stack[-1 - dim], dim),
44                 '\nTry moving the dim of one plate to the left, e.g. dim={}'.format(dim - 1)]))
45         self._stack[-1 - dim] = name
46         return dim
47 
48     def free(self, name, dim):
49         """
50         Free a dimension.
51         """
52         free_idx = -1 - dim  # stack index to free
53         assert self._stack[free_idx] == name
54         self._stack[free_idx] = None
55         while self._stack and self._stack[-1] is None:
56             self._stack.pop()
57 
58 
59 # Handles placement of plate dimensions
60 _DIM_ALLOCATOR = _DimAllocator()
61 
62 
63 class _EnumAllocator(object):
64     """
65     Dimension allocator for internal use by :func:`~pyro.poutine.markov`.
66     There is a single global instance.
67 
68     Note that dimensions are indexed from the right, e.g. -1, -2.
69     Note that ids are simply nonnegative integers here.
70     """
71     def set_first_available_dim(self, first_available_dim):
72         """
73         Set the first available dim, which should be to the left of all
74         :class:`plate` dimensions, e.g. ``-1 - max_plate_nesting``. This should
75         be called once per program. In SVI this should be called only once per
76         (guide,model) pair.
77         """
78         assert first_available_dim < 0, first_available_dim
79         self.next_available_dim = first_available_dim
80         self.next_available_id = 0
81         self.dim_to_id = {}  # only the global ids
82 
83     def allocate(self, scope_dims=None):
84         """
85         Allocate a new recyclable dim and a unique id.
86 
87         If ``scope_dims`` is None, this allocates a global enumeration dim
88         that will never be recycled. If ``scope_dims`` is specified, this
89         allocates a local enumeration dim that can be reused by at any other
90         local site whose scope excludes this site.
91 
92         :param set scope_dims: An optional set of (negative integer)
93             local enumeration dims to avoid when allocating this dim.
94         :return: A pair ``(dim, id)``, where ``dim`` is a negative integer
95             and ``id`` is a nonnegative integer.
96         :rtype: tuple
97         """
98         id_ = self.next_available_id
99         self.next_available_id += 1
100 
101         dim = self.next_available_dim
102         if dim == -float('inf'):
103             raise ValueError("max_plate_nesting must be set to a finite value for parallel enumeration")
104         if scope_dims is None:
105             # allocate a new global dimension
106             self.next_available_dim -= 1
107             self.dim_to_id[dim] = id_
108         else:
109             # allocate a new local dimension
110             while dim in scope_dims:
111                 dim -= 1
112 
113         return dim, id_
114 
115 
116 # Handles placement of enumeration dimensions
117 _ENUM_ALLOCATOR = _EnumAllocator()
118 
119 
120 class NonlocalExit(Exception):
121     """
122     Exception for exiting nonlocally from poutine execution.
123 
124     Used by poutine.EscapeMessenger to return site information.
125     """
126     def __init__(self, site, *args, **kwargs):
127         """
128         :param site: message at a pyro site
129 
130         constructor.  Just stores the input site.
131         """
132         super(NonlocalExit, self).__init__(*args, **kwargs)
133         self.site = site
134 
135     def reset_stack(self):
136         """
137         Reset the state of the frames remaining in the stack.
138         Necessary for multiple re-executions in poutine.queue.
139         """
140         for frame in reversed(_PYRO_STACK):
141             frame._reset()
142             if type(frame).__name__ == "BlockMessenger" and frame.hide_fn(self.site):
143                 break
144 
145 
146 def default_process_message(msg):
147     """
148     Default method for processing messages in inference.
149     :param msg: a message to be processed
150     :returns: None
151     """
152     if msg["done"] or msg["is_observed"]:
153         msg["done"] = True
154         return msg
155 
156     msg["value"] = msg["fn"](*msg["args"], **msg["kwargs"])
157 
158     # after fn has been called, update msg to prevent it from being called again.
159     msg["done"] = True
160 
161 
162 def apply_stack(initial_msg):
163     """
164     Execute the effect stack at a single site according to the following scheme:
165 
166         1. For each ``Messenger`` in the stack from bottom to top,
167            execute ``Messenger._process_message`` with the message;
168            if the message field "stop" is True, stop;
169            otherwise, continue
170         2. Apply default behavior (``default_process_message``) to finish remaining site execution
171         3. For each ``Messenger`` in the stack from top to bottom,
172            execute ``_postprocess_message`` to update the message and internal messenger state with the site results
173         4. If the message field "continuation" is not ``None``, call it with the message
174 
175     :param dict initial_msg: the starting version of the trace site
176     :returns: ``None``
177     """
178     stack = _PYRO_STACK
179     # TODO check at runtime if stack is valid
180 
181     # msg is used to pass information up and down the stack
182     msg = initial_msg
183 
184     pointer = 0
185     # go until time to stop?
186     for frame in reversed(stack):
187 
188         pointer = pointer + 1
189 
190         frame._process_message(msg)
191 
192         if msg["stop"]:
193             break
194 
195     default_process_message(msg)
196 
197     for frame in stack[-pointer:]:  # reversed(stack[0:pointer])
198         frame._postprocess_message(msg)
199 
200     cont = msg["continuation"]
201     if cont is not None:
202         cont(msg)
203 
204     return None
205 
206 
207 def am_i_wrapped():
208     """
209     Checks whether the current computation is wrapped in a poutine.
210     :returns: bool
211     """
212     return len(_PYRO_STACK) > 0
213 
214 
215 def effectful(fn=None, type=None):
216     """
217     :param fn: function or callable that performs an effectful computation
218     :param str type: the type label of the operation, e.g. `"sample"`
219 
220     Wrapper for calling :func:~`pyro.poutine.runtime.apply_stack` to apply any active effects.
221     """
222     if fn is None:
223         return functools.partial(effectful, type=type)
224 
225     if getattr(fn, "_is_effectful", None):
226         return fn
227 
228     assert type is not None, "must provide a type label for operation {}".format(fn)
229     assert type != "message", "cannot use 'message' as keyword"
230 
231     def _fn(*args, **kwargs):
232 
233         name = kwargs.pop("name", None)
234         infer = kwargs.pop("infer", {})
235 
236         value = kwargs.pop("obs", None)
237         is_observed = value is not None
238 
239         if not am_i_wrapped():
240             return fn(*args, **kwargs)
241         else:
242             msg = {
243                 "type": type,
244                 "name": name,
245                 "fn": fn,
246                 "is_observed": is_observed,
247                 "args": args,
248                 "kwargs": kwargs,
249                 "value": value,
250                 "scale": 1.0,
251                 "mask": None,
252                 "cond_indep_stack": (),
253                 "done": False,
254                 "stop": False,
255                 "continuation": None,
256                 "infer": infer,
257             }
258             # apply the stack and return its return value
259             apply_stack(msg)
260             return msg["value"]
261     _fn._is_effectful = True
262     return _fn
263
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pyro/poutine/runtime.py b/pyro/poutine/runtime.py
--- a/pyro/poutine/runtime.py
+++ b/pyro/poutine/runtime.py
@@ -149,7 +149,7 @@
     :param msg: a message to be processed
     :returns: None
     """
-    if msg["done"] or msg["is_observed"]:
+    if msg["done"] or msg["is_observed"] or msg["value"] is not None:
         msg["done"] = True
         return msg

{"golden_diff": "diff --git a/pyro/poutine/runtime.py b/pyro/poutine/runtime.py\n--- a/pyro/poutine/runtime.py\n+++ b/pyro/poutine/runtime.py\n@@ -149,7 +149,7 @@\n     :param msg: a message to be processed\n     :returns: None\n     \"\"\"\n-    if msg[\"done\"] or msg[\"is_observed\"]:\n+    if msg[\"done\"] or msg[\"is_observed\"] or msg[\"value\"] is not None:\n         msg[\"done\"] = True\n         return msg\n", "issue": "[FR] Add tutorial on implementing new effects\nUsers at PROBPROG 2018 requested a tutorial on high-level Pyro architecture including advanced features like poutines.  This issue proposes adding a tutorial on implementing a new effect handler.\r\n\r\nWhereas #1553 should aim to explain Pyro's architecture in a simplified way, this tutorial should prepare developers to make changes to Pyro.\n", "before_files": [{"content": "import functools\n\nfrom pyro.params.param_store import _MODULE_NAMESPACE_DIVIDER, ParamStoreDict  # noqa: F401\n\n# the global pyro stack\n_PYRO_STACK = []\n\n# the global ParamStore\n_PYRO_PARAM_STORE = ParamStoreDict()\n\n\nclass _DimAllocator(object):\n    \"\"\"\n    Dimension allocator for internal use by :class:`plate`.\n    There is a single global instance.\n\n    Note that dimensions are indexed from the right, e.g. -1, -2.\n    \"\"\"\n    def __init__(self):\n        self._stack = []  # in reverse orientation of log_prob.shape\n\n    def allocate(self, name, dim):\n        \"\"\"\n        Allocate a dimension to an :class:`plate` with given name.\n        Dim should be either None for automatic allocation or a negative\n        integer for manual allocation.\n        \"\"\"\n        if name in self._stack:\n            raise ValueError('duplicate plate \"{}\"'.format(name))\n        if dim is None:\n            # Automatically designate the rightmost available dim for allocation.\n            dim = -1\n            while -dim <= len(self._stack) and self._stack[-1 - dim] is not None:\n                dim -= 1\n        elif dim >= 0:\n            raise ValueError('Expected dim < 0 to index from the right, actual {}'.format(dim))\n\n        # Allocate the requested dimension.\n        while dim < -len(self._stack):\n            self._stack.append(None)\n        if self._stack[-1 - dim] is not None:\n            raise ValueError('\\n'.join([\n                'at plates \"{}\" and \"{}\", collide at dim={}'.format(name, self._stack[-1 - dim], dim),\n                '\\nTry moving the dim of one plate to the left, e.g. dim={}'.format(dim - 1)]))\n        self._stack[-1 - dim] = name\n        return dim\n\n    def free(self, name, dim):\n        \"\"\"\n        Free a dimension.\n        \"\"\"\n        free_idx = -1 - dim  # stack index to free\n        assert self._stack[free_idx] == name\n        self._stack[free_idx] = None\n        while self._stack and self._stack[-1] is None:\n            self._stack.pop()\n\n\n# Handles placement of plate dimensions\n_DIM_ALLOCATOR = _DimAllocator()\n\n\nclass _EnumAllocator(object):\n    \"\"\"\n    Dimension allocator for internal use by :func:`~pyro.poutine.markov`.\n    There is a single global instance.\n\n    Note that dimensions are indexed from the right, e.g. -1, -2.\n    Note that ids are simply nonnegative integers here.\n    \"\"\"\n    def set_first_available_dim(self, first_available_dim):\n        \"\"\"\n        Set the first available dim, which should be to the left of all\n        :class:`plate` dimensions, e.g. ``-1 - max_plate_nesting``. This should\n        be called once per program. In SVI this should be called only once per\n        (guide,model) pair.\n        \"\"\"\n        assert first_available_dim < 0, first_available_dim\n        self.next_available_dim = first_available_dim\n        self.next_available_id = 0\n        self.dim_to_id = {}  # only the global ids\n\n    def allocate(self, scope_dims=None):\n        \"\"\"\n        Allocate a new recyclable dim and a unique id.\n\n        If ``scope_dims`` is None, this allocates a global enumeration dim\n        that will never be recycled. If ``scope_dims`` is specified, this\n        allocates a local enumeration dim that can be reused by at any other\n        local site whose scope excludes this site.\n\n        :param set scope_dims: An optional set of (negative integer)\n            local enumeration dims to avoid when allocating this dim.\n        :return: A pair ``(dim, id)``, where ``dim`` is a negative integer\n            and ``id`` is a nonnegative integer.\n        :rtype: tuple\n        \"\"\"\n        id_ = self.next_available_id\n        self.next_available_id += 1\n\n        dim = self.next_available_dim\n        if dim == -float('inf'):\n            raise ValueError(\"max_plate_nesting must be set to a finite value for parallel enumeration\")\n        if scope_dims is None:\n            # allocate a new global dimension\n            self.next_available_dim -= 1\n            self.dim_to_id[dim] = id_\n        else:\n            # allocate a new local dimension\n            while dim in scope_dims:\n                dim -= 1\n\n        return dim, id_\n\n\n# Handles placement of enumeration dimensions\n_ENUM_ALLOCATOR = _EnumAllocator()\n\n\nclass NonlocalExit(Exception):\n    \"\"\"\n    Exception for exiting nonlocally from poutine execution.\n\n    Used by poutine.EscapeMessenger to return site information.\n    \"\"\"\n    def __init__(self, site, *args, **kwargs):\n        \"\"\"\n        :param site: message at a pyro site\n\n        constructor.  Just stores the input site.\n        \"\"\"\n        super(NonlocalExit, self).__init__(*args, **kwargs)\n        self.site = site\n\n    def reset_stack(self):\n        \"\"\"\n        Reset the state of the frames remaining in the stack.\n        Necessary for multiple re-executions in poutine.queue.\n        \"\"\"\n        for frame in reversed(_PYRO_STACK):\n            frame._reset()\n            if type(frame).__name__ == \"BlockMessenger\" and frame.hide_fn(self.site):\n                break\n\n\ndef default_process_message(msg):\n    \"\"\"\n    Default method for processing messages in inference.\n    :param msg: a message to be processed\n    :returns: None\n    \"\"\"\n    if msg[\"done\"] or msg[\"is_observed\"]:\n        msg[\"done\"] = True\n        return msg\n\n    msg[\"value\"] = msg[\"fn\"](*msg[\"args\"], **msg[\"kwargs\"])\n\n    # after fn has been called, update msg to prevent it from being called again.\n    msg[\"done\"] = True\n\n\ndef apply_stack(initial_msg):\n    \"\"\"\n    Execute the effect stack at a single site according to the following scheme:\n\n        1. For each ``Messenger`` in the stack from bottom to top,\n           execute ``Messenger._process_message`` with the message;\n           if the message field \"stop\" is True, stop;\n           otherwise, continue\n        2. Apply default behavior (``default_process_message``) to finish remaining site execution\n        3. For each ``Messenger`` in the stack from top to bottom,\n           execute ``_postprocess_message`` to update the message and internal messenger state with the site results\n        4. If the message field \"continuation\" is not ``None``, call it with the message\n\n    :param dict initial_msg: the starting version of the trace site\n    :returns: ``None``\n    \"\"\"\n    stack = _PYRO_STACK\n    # TODO check at runtime if stack is valid\n\n    # msg is used to pass information up and down the stack\n    msg = initial_msg\n\n    pointer = 0\n    # go until time to stop?\n    for frame in reversed(stack):\n\n        pointer = pointer + 1\n\n        frame._process_message(msg)\n\n        if msg[\"stop\"]:\n            break\n\n    default_process_message(msg)\n\n    for frame in stack[-pointer:]:  # reversed(stack[0:pointer])\n        frame._postprocess_message(msg)\n\n    cont = msg[\"continuation\"]\n    if cont is not None:\n        cont(msg)\n\n    return None\n\n\ndef am_i_wrapped():\n    \"\"\"\n    Checks whether the current computation is wrapped in a poutine.\n    :returns: bool\n    \"\"\"\n    return len(_PYRO_STACK) > 0\n\n\ndef effectful(fn=None, type=None):\n    \"\"\"\n    :param fn: function or callable that performs an effectful computation\n    :param str type: the type label of the operation, e.g. `\"sample\"`\n\n    Wrapper for calling :func:~`pyro.poutine.runtime.apply_stack` to apply any active effects.\n    \"\"\"\n    if fn is None:\n        return functools.partial(effectful, type=type)\n\n    if getattr(fn, \"_is_effectful\", None):\n        return fn\n\n    assert type is not None, \"must provide a type label for operation {}\".format(fn)\n    assert type != \"message\", \"cannot use 'message' as keyword\"\n\n    def _fn(*args, **kwargs):\n\n        name = kwargs.pop(\"name\", None)\n        infer = kwargs.pop(\"infer\", {})\n\n        value = kwargs.pop(\"obs\", None)\n        is_observed = value is not None\n\n        if not am_i_wrapped():\n            return fn(*args, **kwargs)\n        else:\n            msg = {\n                \"type\": type,\n                \"name\": name,\n                \"fn\": fn,\n                \"is_observed\": is_observed,\n                \"args\": args,\n                \"kwargs\": kwargs,\n                \"value\": value,\n                \"scale\": 1.0,\n                \"mask\": None,\n                \"cond_indep_stack\": (),\n                \"done\": False,\n                \"stop\": False,\n                \"continuation\": None,\n                \"infer\": infer,\n            }\n            # apply the stack and return its return value\n            apply_stack(msg)\n            return msg[\"value\"]\n    _fn._is_effectful = True\n    return _fn\n", "path": "pyro/poutine/runtime.py"}], "after_files": [{"content": "import functools\n\nfrom pyro.params.param_store import _MODULE_NAMESPACE_DIVIDER, ParamStoreDict  # noqa: F401\n\n# the global pyro stack\n_PYRO_STACK = []\n\n# the global ParamStore\n_PYRO_PARAM_STORE = ParamStoreDict()\n\n\nclass _DimAllocator(object):\n    \"\"\"\n    Dimension allocator for internal use by :class:`plate`.\n    There is a single global instance.\n\n    Note that dimensions are indexed from the right, e.g. -1, -2.\n    \"\"\"\n    def __init__(self):\n        self._stack = []  # in reverse orientation of log_prob.shape\n\n    def allocate(self, name, dim):\n        \"\"\"\n        Allocate a dimension to an :class:`plate` with given name.\n        Dim should be either None for automatic allocation or a negative\n        integer for manual allocation.\n        \"\"\"\n        if name in self._stack:\n            raise ValueError('duplicate plate \"{}\"'.format(name))\n        if dim is None:\n            # Automatically designate the rightmost available dim for allocation.\n            dim = -1\n            while -dim <= len(self._stack) and self._stack[-1 - dim] is not None:\n                dim -= 1\n        elif dim >= 0:\n            raise ValueError('Expected dim < 0 to index from the right, actual {}'.format(dim))\n\n        # Allocate the requested dimension.\n        while dim < -len(self._stack):\n            self._stack.append(None)\n        if self._stack[-1 - dim] is not None:\n            raise ValueError('\\n'.join([\n                'at plates \"{}\" and \"{}\", collide at dim={}'.format(name, self._stack[-1 - dim], dim),\n                '\\nTry moving the dim of one plate to the left, e.g. dim={}'.format(dim - 1)]))\n        self._stack[-1 - dim] = name\n        return dim\n\n    def free(self, name, dim):\n        \"\"\"\n        Free a dimension.\n        \"\"\"\n        free_idx = -1 - dim  # stack index to free\n        assert self._stack[free_idx] == name\n        self._stack[free_idx] = None\n        while self._stack and self._stack[-1] is None:\n            self._stack.pop()\n\n\n# Handles placement of plate dimensions\n_DIM_ALLOCATOR = _DimAllocator()\n\n\nclass _EnumAllocator(object):\n    \"\"\"\n    Dimension allocator for internal use by :func:`~pyro.poutine.markov`.\n    There is a single global instance.\n\n    Note that dimensions are indexed from the right, e.g. -1, -2.\n    Note that ids are simply nonnegative integers here.\n    \"\"\"\n    def set_first_available_dim(self, first_available_dim):\n        \"\"\"\n        Set the first available dim, which should be to the left of all\n        :class:`plate` dimensions, e.g. ``-1 - max_plate_nesting``. This should\n        be called once per program. In SVI this should be called only once per\n        (guide,model) pair.\n        \"\"\"\n        assert first_available_dim < 0, first_available_dim\n        self.next_available_dim = first_available_dim\n        self.next_available_id = 0\n        self.dim_to_id = {}  # only the global ids\n\n    def allocate(self, scope_dims=None):\n        \"\"\"\n        Allocate a new recyclable dim and a unique id.\n\n        If ``scope_dims`` is None, this allocates a global enumeration dim\n        that will never be recycled. If ``scope_dims`` is specified, this\n        allocates a local enumeration dim that can be reused by at any other\n        local site whose scope excludes this site.\n\n        :param set scope_dims: An optional set of (negative integer)\n            local enumeration dims to avoid when allocating this dim.\n        :return: A pair ``(dim, id)``, where ``dim`` is a negative integer\n            and ``id`` is a nonnegative integer.\n        :rtype: tuple\n        \"\"\"\n        id_ = self.next_available_id\n        self.next_available_id += 1\n\n        dim = self.next_available_dim\n        if dim == -float('inf'):\n            raise ValueError(\"max_plate_nesting must be set to a finite value for parallel enumeration\")\n        if scope_dims is None:\n            # allocate a new global dimension\n            self.next_available_dim -= 1\n            self.dim_to_id[dim] = id_\n        else:\n            # allocate a new local dimension\n            while dim in scope_dims:\n                dim -= 1\n\n        return dim, id_\n\n\n# Handles placement of enumeration dimensions\n_ENUM_ALLOCATOR = _EnumAllocator()\n\n\nclass NonlocalExit(Exception):\n    \"\"\"\n    Exception for exiting nonlocally from poutine execution.\n\n    Used by poutine.EscapeMessenger to return site information.\n    \"\"\"\n    def __init__(self, site, *args, **kwargs):\n        \"\"\"\n        :param site: message at a pyro site\n\n        constructor.  Just stores the input site.\n        \"\"\"\n        super(NonlocalExit, self).__init__(*args, **kwargs)\n        self.site = site\n\n    def reset_stack(self):\n        \"\"\"\n        Reset the state of the frames remaining in the stack.\n        Necessary for multiple re-executions in poutine.queue.\n        \"\"\"\n        for frame in reversed(_PYRO_STACK):\n            frame._reset()\n            if type(frame).__name__ == \"BlockMessenger\" and frame.hide_fn(self.site):\n                break\n\n\ndef default_process_message(msg):\n    \"\"\"\n    Default method for processing messages in inference.\n    :param msg: a message to be processed\n    :returns: None\n    \"\"\"\n    if msg[\"done\"] or msg[\"is_observed\"] or msg[\"value\"] is not None:\n        msg[\"done\"] = True\n        return msg\n\n    msg[\"value\"] = msg[\"fn\"](*msg[\"args\"], **msg[\"kwargs\"])\n\n    # after fn has been called, update msg to prevent it from being called again.\n    msg[\"done\"] = True\n\n\ndef apply_stack(initial_msg):\n    \"\"\"\n    Execute the effect stack at a single site according to the following scheme:\n\n        1. For each ``Messenger`` in the stack from bottom to top,\n           execute ``Messenger._process_message`` with the message;\n           if the message field \"stop\" is True, stop;\n           otherwise, continue\n        2. Apply default behavior (``default_process_message``) to finish remaining site execution\n        3. For each ``Messenger`` in the stack from top to bottom,\n           execute ``_postprocess_message`` to update the message and internal messenger state with the site results\n        4. If the message field \"continuation\" is not ``None``, call it with the message\n\n    :param dict initial_msg: the starting version of the trace site\n    :returns: ``None``\n    \"\"\"\n    stack = _PYRO_STACK\n    # TODO check at runtime if stack is valid\n\n    # msg is used to pass information up and down the stack\n    msg = initial_msg\n\n    pointer = 0\n    # go until time to stop?\n    for frame in reversed(stack):\n\n        pointer = pointer + 1\n\n        frame._process_message(msg)\n\n        if msg[\"stop\"]:\n            break\n\n    default_process_message(msg)\n\n    for frame in stack[-pointer:]:  # reversed(stack[0:pointer])\n        frame._postprocess_message(msg)\n\n    cont = msg[\"continuation\"]\n    if cont is not None:\n        cont(msg)\n\n    return None\n\n\ndef am_i_wrapped():\n    \"\"\"\n    Checks whether the current computation is wrapped in a poutine.\n    :returns: bool\n    \"\"\"\n    return len(_PYRO_STACK) > 0\n\n\ndef effectful(fn=None, type=None):\n    \"\"\"\n    :param fn: function or callable that performs an effectful computation\n    :param str type: the type label of the operation, e.g. `\"sample\"`\n\n    Wrapper for calling :func:~`pyro.poutine.runtime.apply_stack` to apply any active effects.\n    \"\"\"\n    if fn is None:\n        return functools.partial(effectful, type=type)\n\n    if getattr(fn, \"_is_effectful\", None):\n        return fn\n\n    assert type is not None, \"must provide a type label for operation {}\".format(fn)\n    assert type != \"message\", \"cannot use 'message' as keyword\"\n\n    def _fn(*args, **kwargs):\n\n        name = kwargs.pop(\"name\", None)\n        infer = kwargs.pop(\"infer\", {})\n\n        value = kwargs.pop(\"obs\", None)\n        is_observed = value is not None\n\n        if not am_i_wrapped():\n            return fn(*args, **kwargs)\n        else:\n            msg = {\n                \"type\": type,\n                \"name\": name,\n                \"fn\": fn,\n                \"is_observed\": is_observed,\n                \"args\": args,\n                \"kwargs\": kwargs,\n                \"value\": value,\n                \"scale\": 1.0,\n                \"mask\": None,\n                \"cond_indep_stack\": (),\n                \"done\": False,\n                \"stop\": False,\n                \"continuation\": None,\n                \"infer\": infer,\n            }\n            # apply the stack and return its return value\n            apply_stack(msg)\n            return msg[\"value\"]\n    _fn._is_effectful = True\n    return _fn\n", "path": "pyro/poutine/runtime.py"}]}