In Haskell Pipes, suppose I am writing f :: Producer a m ()
and I am inside a do block with respect to m
(Edit: this doesn’t make sense; I want a producer do block). Inside this do block, I want to yield from g :: Producer a m ()
before returning to my do block. How do I accomplish that?
In my particular case, a = ()
and m = State s
, and my producers are managing some branching behavior which only affects the state. g
happens to yield only once, so in Python language, it's a context manager that changes some state, yields, then cleans up for itself. So in Python I could "yield from g" or use @contextmanager
on g
and enter a with
block.
Edit: What I'm looking for is to write branches for a backtracking function, something like
do
whenM accept_this_one (lift move_to_next)
forM_ choices \i ->
when (notM (bad_choice i)) (lift (select i))
g
is like select i
, so think of g
as i_type -> Producer () m ()
.
move_to_next
and select
are both like context managers, cleaning up after themselves. So the state changes from move_to_next
should last until (the end of the block? Here I'm confused. But certainly longer than the single line.) This should give something one can iterate over, and it manages the state for you.
In response to a question about how the state is affected, f
should incorporate state changes from g
, in the way it would in Python if we said yield from g
, and f
and g
had access to common state.
Edit2: Here's a Python version of what I want:
@contextmanager
def move_to_next():
# do stuff
yield
# undo stuff
return
@contextmanager
def selected(i):
# do stuff
yield
# undo stuff
return
if accept_this_one():
cm = move_to_next()
else:
cm = contextlib.nullcontext()
with cm:
for i in choices:
if not bad_choice(i):
with selected(i):
# Do stuff if you want
yield
Edit 3: Maybe this?
select : i_type -> Prod () m ()
move_to_next : Prod () m ()
accept_this_one : m bool
do
let x = ifM (lift accept_this_one)
then move_to_next
else yield
x ~> \_ -> forM_ choices \i ->
when (notM (bad_choice i)) (select i)
yield
(effectively, in this context) has the typea -> Producer a m ()
. You cannot use it in thedo
block of am
, only thedo
block of aProducer a m ()
. If you need to use aState
, you need tolift
it toProducer
first: