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 ?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With