比方说,我有以下类型:
type LinkID = Int
data Link = Link {
lid :: LinkID,
llength :: Int
}
data Snap = Snap {
slid :: LinkID,
slength :: Int
}
现在,我想编写一个基于管道的函数来执行此操作:
getSnaps :: LinkID -> [Link] -> [Snap] -> [(LinkID, [Snap])]
getSnaps l lks snp = map (\x -> (lid x, filter (\y -> lid x == slid y) snp)) a
where a = filter (\x -> lid x > l) lks
假设我已经有了 Link
和 Snap
的 Producers,我如何通过这两个在 Pipes 世界中实现上面的 getSnaps
功能制作人:
psnap :: Producer Snap IO ()
psnap = undefined
plink :: Producer Link IO ()
plink = undefined
psnap
和plink
的实际类型比较复杂(使用attoparsec-pipes创建出来),但我想知道如何实现getSnaps的功能来自 psnap
和 plink
。有解决此类问题的正确方法吗?
最佳答案
我提出的解决方案与您的代码非常相似。我刚刚将 map
替换为 Pipes.Prelude.map
并将其中一个过滤器替换为 Pipes.Prelude.filter
:
import Pipes
import qualified Pipes.Prelude as Pipes
type LinkID = Int
data Link = Link
{ lid :: LinkID
, llength :: Int
}
data Snap = Snap
{ slid :: LinkID
, slength :: Int
}
getSnaps
:: Monad m
=> LinkID
-> Producer Link m ()
-> Producer Snap m ()
-> Producer (LinkID, [Snap]) m ()
getSnaps l lks snp = do
snp' <- lift (Pipes.toListM snp) -- Cache `snp` into the list `snp'`
lks >-> Pipes.filter (\x -> lid x > l)
>-> Pipes.map (\x -> (lid x, filter (\y -> lid x == slid y) snp'))
请注意,有一个重要的部分,即上述解决方案严格地将 snp
Producer
的内容加载到列表 snp'
。这样做的原因是我们要重复使用列表的内容,所以我们需要将整个列表缓存在内存中,以便重复使用。
关于haskell - 为简单函数管道等效代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24663098/