简体   繁体   English

Haskell 管道中的“产量”

[英]"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).Haskell Pipes中,假设我正在编写f:: Producer am ()并且我在关于m的 do 块内(编辑:这没有意义;我想要一个生产者 do 块)。 Inside this do block, I want to yield from g:: Producer am () before returning to my do block.在这个 do 块中,我想在返回到我的 do 块之前从g:: Producer am ()产生。 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.在我的特殊情况下, a = ()m = State s ,我的生产者正在管理一些仅影响 state.g 的分支行为g恰好只产生一次,所以在 Python 语言中,它是一个上下文管理器,它改变了一些 state,产量,然后自行清理。 So in Python I could "yield from g" or use @contextmanager on g and enter a with block.因此,在 Python 中,我可以“从 g 中产生”或在g上使用@contextmanager并输入with块。

Edit: What I'm looking for is to write branches for a backtracking function, something like编辑:我正在寻找的是为回溯 function 编写分支,比如

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 () . g就像select i ,因此将g视为i_type -> Producer () m ()

move_to_next and select are both like context managers, cleaning up after themselves. move_to_nextselect都像上下文管理器,自行清理。 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.所以 state 从move_to_next的变化应该持续到(块的末尾?在这里我很困惑。但肯定比单行更长。)这应该提供一些可以迭代的东西,它会为你管理 state。

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.在回答有关 state 如何受到影响的问题时, f应该合并 g 的 state 更改,如果我们说yield from g g fg可以访问公共 state,那么它会在 Python 中这样做。

Edit2: Here's a Python version of what I want: Edit2:这是我想要的 Python 版本:

@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?编辑3:也许这个?

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 () . yield (实际上,在这种情况下)具有类型a -> Producer am () You cannot use it in the do block of a m , only the do block of a Producer am () .您不能在mdo块中使用它,只能在Producer am ()do块中使用它。 If you need to use a State , you need to lift it to Producer first:如果你需要使用一个State ,你需要先将它liftProducer

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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