gsp*_*spr 5 haskell api-design haskell-pipes
我正在为管道接口中的某些编码包装C库,但我已经做了一些需要做出的设计决策.
在设置C库之后,我们保持编码器上下文.有了这个,我们可以编码,或者改变一些参数(让我们将Haskell接口调用到最后一个函数tune :: Context -> Int -> IO ()).我的问题分为两部分:
Pipe Foo Bar IO (),但我也想曝光tune.由于编码上下文的同时使用必须受到锁定保护,因此我需要在管道中的每次迭代时锁定,并tune使用相同的锁进行保护.但现在我觉得我正在强迫用户隐藏锁定.我在这里吠叫错了吗?这种情况通常如何在管道生态系统中得到解决?在我的情况下,我希望我的特定代码所属的管道始终在其自己的线程中运行,同时进行调整,但我不想强迫任何用户使用这种观点.管道生态系统中的其他软件包似乎也不会强迫用户使用.IO在管道被破坏时处理这些事情(在这种情况下执行som 动作)?一个具体的例子是包装压缩库,在这种情况下,上面可以是:
谢谢......这可能都很明显,但我对管道生态系统还很陌生.
编辑:发帖后阅读,我很确定这是我在这里问过的最模糊的问题.啊! 对不起;-)
关于(1),一般的解决方案是将您的Pipe类型更改为:
Pipe (Either (Context, Int) Foo) Bar IO ()
Run Code Online (Sandbox Code Playgroud)
换句话说,它接受Foo输入和tune请求,并在内部进行处理。
因此,我们假设您有两个对应Producer于输入和调整请求的并发:
producer1 :: Producer Foo IO ()
producer2 :: Producer (Context, Int) IO ()
Run Code Online (Sandbox Code Playgroud)
您可以使用它们pipes-concurrency来创建一个缓冲区,将它们都输入其中,如下所示:
example = do
(output, input) <- spawn Unbounded
-- input :: Input (Either (Context, Int) Foo)
-- output :: Output (Either (Context, Int) Foo)
let io1 = runEffect $ producer1 >-> Pipes.Prelude.map Right >-> toOutput output
io2 = runEffect $ producer2 >-> Pipes.Prelude.map Left >-> toOutput output
as <- mapM async [io1, io2]
runEffect (fromInput >-> yourPipe >-> someConsumer)
mapM_ wait as
Run Code Online (Sandbox Code Playgroud)
您可以pipes-concurrency通过阅读本教程了解有关该库的更多信息。
通过强制所有调整请求通过相同的单线程,Pipe您可以确保不会意外地对该tune函数进行两次并发调用。
关于 (2),您可以通过两种方式使用 获取资源pipes。更复杂的方法是使用该pipes-safe库,它提供了一个bracket可以在 中使用的函数Pipe,但这对于您的目的来说可能有点过分,并且仅用于在管道的生命周期内获取和释放多个资源。一个更简单的解决方案是使用以下with习惯用法来获取管道:
withEncoder :: (Pipe Foo Bar IO () -> IO r) -> IO r
withEncoder k = bracket acquire release $ \resource -> do
k (createPipeFromResource resource)
Run Code Online (Sandbox Code Playgroud)
然后用户只需写:
withEncoder $ \yourPipe -> do
runEffect (someProducer >-> yourPipe >-> someConsumer)
Run Code Online (Sandbox Code Playgroud)
您可以选择使用该managed包,这会稍微简化类型并使获取多个资源变得更加容易。您可以通过阅读我的这篇博文来了解更多信息。
| 归档时间: |
|
| 查看次数: |
218 次 |
| 最近记录: |