sequence-formats-1.6.6.1: src/SequenceFormats/Bed.hs
module SequenceFormats.Bed where
import SequenceFormats.Utils (Chrom (..), consumeProducer,
readFileProd)
import Control.Monad.Trans.Class (lift)
import qualified Data.Attoparsec.ByteString.Char8 as A
import Data.Char (isSpace)
import Pipes (Producer, next, yield)
import Pipes.Safe (MonadSafe)
data BedEntry = BedEntry Chrom Int Int
deriving (Show, Eq)
bedFileParser :: A.Parser BedEntry
bedFileParser = BedEntry <$> chrom <* A.skipSpace <*> A.decimal <* A.skipSpace <*> A.decimal <* A.endOfLine
where
chrom = Chrom <$> A.takeTill isSpace
readBedFile :: (MonadSafe m) => FilePath -> Producer BedEntry m ()
readBedFile bedFile = consumeProducer bedFileParser (readFileProd bedFile)
data IntervalStatus = BedBehind
| BedOn
| BedAhead
filterThroughBed :: (Monad m) => Producer BedEntry m () -> (a -> (Chrom, Int)) -> Producer a m () -> Producer a m ()
filterThroughBed bedProd posFunc gProd = do
b <- lift $ next bedProd
let (bedCurrent, bedRest) = case b of
Left _ -> error "Bed file empty or not readable"
Right r -> r
f' <- lift $ next gProd
let (gCurrent, gRest) = case f' of
Left _ -> error "Genomic stream empty or not readable"
Right r -> r
go bedCurrent gCurrent bedRest gRest
where
go bedCurrent gCurrent bedRest gRest = do
let recurseNextBed = do
b <- lift $ next bedRest
case b of
Left () -> return ()
Right (nextBed, bedRest') -> go nextBed gCurrent bedRest' gRest
recurseNextG = do
f' <- lift $ next gRest
case f' of
Left () -> return ()
Right (nextG, gRest') -> go bedCurrent nextG bedRest gRest'
case bedCurrent `checkIntervalStatus` gCurrent of
BedBehind -> recurseNextBed
BedAhead -> recurseNextG
BedOn -> do
yield gCurrent
recurseNextG
-- checkIntervalStatus :: BedEntry -> a -> IntervalStatus
checkIntervalStatus (BedEntry bedChrom bedStart bedEnd) g =
case bedChrom `compare` (fst . posFunc) g of
LT -> BedBehind
GT -> BedAhead
EQ -> if bedStart + 1 > (snd . posFunc) g then
BedAhead
else
if bedEnd < (snd . posFunc) g then BedBehind else BedOn