Reputation: 48644
Let's say, I have the following types:
type LinkID = Int
data Link = Link {
lid :: LinkID,
llength :: Int
}
data Snap = Snap {
slid :: LinkID,
slength :: Int
}
Now, I want to write a pipes based function which does this:
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
Assumming that I already have Producers of Link
and Snap
, how can I implement the above getSnaps
function in the Pipes world from these two Producers:
psnap :: Producer Snap IO ()
psnap = undefined
plink :: Producer Link IO ()
plink = undefined
The actual types of psnap
and plink
are more involved (created out by using attoparsec-pipes), but I would like to know how to implement the functionality of getSnaps from psnap
and plink
. Is there a proper way to solve this type of problem ?
Upvotes: 3
Views: 146
Reputation: 35089
The solution I came up with is pretty similar to your code. I just replaced map
with Pipes.Prelude.map
and one of the filters with 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'))
Note that there is one non-trivial part, which is that the above solution strictly loads the snp
Producer
's contents into the list snp'
. The reason for this is that we have to use the contents of the list repeatedly, so we need to cache the entire list in memory for repeated usage.
Upvotes: 2