简体   繁体   中英

"Yield from" in Haskell Pipes

In Haskell Pipes , suppose I am writing f:: Producer am () 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 am () 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 type a -> Producer am () . You cannot use it in the do block of a m , only the do block of a Producer am () . If you need to use a State , you need to lift it to Producer first:

f :: Producer s (State s ()) ()
f = do
      x <- lift get
      yield x

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM