{-# LANGUAGE OverloadedStrings #-}
module SequenceFormats.Eigenstrat (EigenstratSnpEntry(..), EigenstratIndEntry(..),
readEigenstratInd, GenoEntry(..), GenoLine, Sex(..),
readEigenstratSnpStdIn, readEigenstratSnpFile,
readEigenstrat, writeEigenstrat, writeEigenstratIndFile, writeEigenstratSnp,
writeEigenstratGeno) where
import SequenceFormats.Utils (Chrom (..),
SeqFormatException (..),
consumeProducer,
readFileProd, word)
import Control.Applicative ((<|>))
import Control.Exception (throw)
import Control.Monad (forM_, void)
import Control.Monad.Catch (MonadThrow)
import Control.Monad.IO.Class (MonadIO, liftIO)
import qualified Data.Attoparsec.ByteString.Char8 as A
import qualified Data.ByteString.Char8 as B
import Data.Vector (Vector, fromList, toList)
import Pipes (Consumer, Pipe, Producer,
cat, for, yield, (>->))
import qualified Pipes.ByteString as PB
import qualified Pipes.Prelude as P
import Pipes.Safe (MonadSafe)
import qualified Pipes.Safe.Prelude as PS
import System.IO (Handle, IOMode (..),
hPutStrLn, withFile)
data EigenstratSnpEntry = EigenstratSnpEntry
{ EigenstratSnpEntry -> Chrom
snpChrom :: Chrom
, EigenstratSnpEntry -> Int
snpPos :: Int
, EigenstratSnpEntry -> Double
snpGeneticPos :: Double
, EigenstratSnpEntry -> ByteString
snpId :: B.ByteString
, EigenstratSnpEntry -> Char
snpRef :: Char
, EigenstratSnpEntry -> Char
snpAlt :: Char
}
deriving (EigenstratSnpEntry -> EigenstratSnpEntry -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: EigenstratSnpEntry -> EigenstratSnpEntry -> Bool
$c/= :: EigenstratSnpEntry -> EigenstratSnpEntry -> Bool
== :: EigenstratSnpEntry -> EigenstratSnpEntry -> Bool
$c== :: EigenstratSnpEntry -> EigenstratSnpEntry -> Bool
Eq, Int -> EigenstratSnpEntry -> ShowS
[EigenstratSnpEntry] -> ShowS
EigenstratSnpEntry -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [EigenstratSnpEntry] -> ShowS
$cshowList :: [EigenstratSnpEntry] -> ShowS
show :: EigenstratSnpEntry -> String
$cshow :: EigenstratSnpEntry -> String
showsPrec :: Int -> EigenstratSnpEntry -> ShowS
$cshowsPrec :: Int -> EigenstratSnpEntry -> ShowS
Show)
data EigenstratIndEntry = EigenstratIndEntry String Sex String
deriving (EigenstratIndEntry -> EigenstratIndEntry -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: EigenstratIndEntry -> EigenstratIndEntry -> Bool
$c/= :: EigenstratIndEntry -> EigenstratIndEntry -> Bool
== :: EigenstratIndEntry -> EigenstratIndEntry -> Bool
$c== :: EigenstratIndEntry -> EigenstratIndEntry -> Bool
Eq, Int -> EigenstratIndEntry -> ShowS
[EigenstratIndEntry] -> ShowS
EigenstratIndEntry -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [EigenstratIndEntry] -> ShowS
$cshowList :: [EigenstratIndEntry] -> ShowS
show :: EigenstratIndEntry -> String
$cshow :: EigenstratIndEntry -> String
showsPrec :: Int -> EigenstratIndEntry -> ShowS
$cshowsPrec :: Int -> EigenstratIndEntry -> ShowS
Show)
data Sex = Male
| Female
| Unknown
deriving (Sex -> Sex -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Sex -> Sex -> Bool
$c/= :: Sex -> Sex -> Bool
== :: Sex -> Sex -> Bool
$c== :: Sex -> Sex -> Bool
Eq, Int -> Sex -> ShowS
[Sex] -> ShowS
Sex -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Sex] -> ShowS
$cshowList :: [Sex] -> ShowS
show :: Sex -> String
$cshow :: Sex -> String
showsPrec :: Int -> Sex -> ShowS
$cshowsPrec :: Int -> Sex -> ShowS
Show)
data GenoEntry = HomRef
| Het
| HomAlt
| Missing
deriving (GenoEntry -> GenoEntry -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: GenoEntry -> GenoEntry -> Bool
$c/= :: GenoEntry -> GenoEntry -> Bool
== :: GenoEntry -> GenoEntry -> Bool
$c== :: GenoEntry -> GenoEntry -> Bool
Eq, Int -> GenoEntry -> ShowS
[GenoEntry] -> ShowS
GenoEntry -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [GenoEntry] -> ShowS
$cshowList :: [GenoEntry] -> ShowS
show :: GenoEntry -> String
$cshow :: GenoEntry -> String
showsPrec :: Int -> GenoEntry -> ShowS
$cshowsPrec :: Int -> GenoEntry -> ShowS
Show)
type GenoLine = Vector GenoEntry
eigenstratSnpParser :: A.Parser EigenstratSnpEntry
eigenstratSnpParser :: Parser EigenstratSnpEntry
eigenstratSnpParser = do
ByteString
snpId_ <- forall (f :: * -> *) a. Alternative f => f a -> f ()
A.skipMany Parser Char
A.space forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Parser ByteString ByteString
word
ByteString
chrom <- forall (f :: * -> *) a. Alternative f => f a -> f ()
A.skipMany1 Parser Char
A.space forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Parser ByteString ByteString
word
Double
geneticPos <- forall (f :: * -> *) a. Alternative f => f a -> f ()
A.skipMany1 Parser Char
A.space forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Parser ByteString Double
A.double
Int
pos <- forall (f :: * -> *) a. Alternative f => f a -> f ()
A.skipMany1 Parser Char
A.space forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall a. Integral a => Parser a
A.decimal
Char
ref <- forall (f :: * -> *) a. Alternative f => f a -> f ()
A.skipMany1 Parser Char
A.space forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Char -> Bool) -> Parser Char
A.satisfy (String -> Char -> Bool
A.inClass String
"ACTGNX")
Char
alt <- forall (f :: * -> *) a. Alternative f => f a -> f ()
A.skipMany1 Parser Char
A.space forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Char -> Bool) -> Parser Char
A.satisfy (String -> Char -> Bool
A.inClass String
"ACTGNX")
forall (f :: * -> *) a. Functor f => f a -> f ()
void Parser ()
A.endOfLine
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Chrom
-> Int
-> Double
-> ByteString
-> Char
-> Char
-> EigenstratSnpEntry
EigenstratSnpEntry (ByteString -> Chrom
Chrom ByteString
chrom) Int
pos Double
geneticPos ByteString
snpId_ Char
ref Char
alt
eigenstratIndParser :: A.Parser EigenstratIndEntry
eigenstratIndParser :: Parser EigenstratIndEntry
eigenstratIndParser = do
forall (f :: * -> *) a. Alternative f => f a -> f ()
A.skipMany Parser Char
A.space
ByteString
name <- Parser ByteString ByteString
word
forall (f :: * -> *) a. Alternative f => f a -> f ()
A.skipMany1 Parser Char
A.space
Sex
sex <- Parser Sex
parseSex
forall (f :: * -> *) a. Alternative f => f a -> f ()
A.skipMany1 Parser Char
A.space
ByteString
popName <- Parser ByteString ByteString
word
forall (f :: * -> *) a. Functor f => f a -> f ()
void Parser ()
A.endOfLine
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ String -> Sex -> String -> EigenstratIndEntry
EigenstratIndEntry (ByteString -> String
B.unpack ByteString
name) Sex
sex (ByteString -> String
B.unpack ByteString
popName)
parseSex :: A.Parser Sex
parseSex :: Parser Sex
parseSex = Parser Sex
parseMale forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser Sex
parseFemale forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser Sex
parseUnknown
where
parseMale :: Parser Sex
parseMale = Char -> Parser Char
A.char Char
'M' forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (m :: * -> *) a. Monad m => a -> m a
return Sex
Male
parseFemale :: Parser Sex
parseFemale = Char -> Parser Char
A.char Char
'F' forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (m :: * -> *) a. Monad m => a -> m a
return Sex
Female
parseUnknown :: Parser Sex
parseUnknown = Char -> Parser Char
A.char Char
'U' forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (m :: * -> *) a. Monad m => a -> m a
return Sex
Unknown
readEigenstratInd :: (MonadIO m) => FilePath -> m [EigenstratIndEntry]
readEigenstratInd :: forall (m :: * -> *). MonadIO m => String -> m [EigenstratIndEntry]
readEigenstratInd String
fn =
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall r. String -> IOMode -> (Handle -> IO r) -> IO r
withFile String
fn IOMode
ReadMode forall a b. (a -> b) -> a -> b
$ \Handle
handle ->
forall (m :: * -> *) a. Monad m => Producer a m () -> m [a]
P.toListM forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a.
MonadThrow m =>
Parser a -> Producer ByteString m () -> Producer a m ()
consumeProducer Parser EigenstratIndEntry
eigenstratIndParser (forall (m :: * -> *).
MonadIO m =>
Handle -> Producer' ByteString m ()
PB.fromHandle Handle
handle)
eigenstratGenoParser :: A.Parser GenoLine
eigenstratGenoParser :: Parser GenoLine
eigenstratGenoParser = do
ByteString
line <- (Char -> Bool) -> Parser ByteString ByteString
A.takeWhile1 Char -> Bool
isValidNum
forall (f :: * -> *) a. Functor f => f a -> f ()
void Parser ()
A.endOfLine
forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> Vector a
fromList forall a b. (a -> b) -> a -> b
$ do
Char
l <- ByteString -> String
B.unpack ByteString
line
case Char
l of
Char
'0' -> forall (m :: * -> *) a. Monad m => a -> m a
return GenoEntry
HomAlt
Char
'1' -> forall (m :: * -> *) a. Monad m => a -> m a
return GenoEntry
Het
Char
'2' -> forall (m :: * -> *) a. Monad m => a -> m a
return GenoEntry
HomRef
Char
'9' -> forall (m :: * -> *) a. Monad m => a -> m a
return GenoEntry
Missing
Char
_ -> forall a. HasCallStack => String -> a
error String
"this should never happen"
where
isValidNum :: Char -> Bool
isValidNum Char
c = Char
c forall a. Eq a => a -> a -> Bool
== Char
'0' Bool -> Bool -> Bool
|| Char
c forall a. Eq a => a -> a -> Bool
== Char
'1' Bool -> Bool -> Bool
|| Char
c forall a. Eq a => a -> a -> Bool
== Char
'2' Bool -> Bool -> Bool
|| Char
c forall a. Eq a => a -> a -> Bool
== Char
'9'
readEigenstratSnpStdIn :: (MonadThrow m, MonadIO m) => Producer EigenstratSnpEntry m ()
readEigenstratSnpStdIn :: forall (m :: * -> *).
(MonadThrow m, MonadIO m) =>
Producer EigenstratSnpEntry m ()
readEigenstratSnpStdIn = forall (m :: * -> *) a.
MonadThrow m =>
Parser a -> Producer ByteString m () -> Producer a m ()
consumeProducer Parser EigenstratSnpEntry
eigenstratSnpParser forall (m :: * -> *). MonadIO m => Producer' ByteString m ()
PB.stdin
readEigenstratSnpFile :: (MonadSafe m) => FilePath -> Producer EigenstratSnpEntry m ()
readEigenstratSnpFile :: forall (m :: * -> *).
MonadSafe m =>
String -> Producer EigenstratSnpEntry m ()
readEigenstratSnpFile = forall (m :: * -> *) a.
MonadThrow m =>
Parser a -> Producer ByteString m () -> Producer a m ()
consumeProducer Parser EigenstratSnpEntry
eigenstratSnpParser forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *).
MonadSafe m =>
String -> Producer ByteString m ()
readFileProd
readEigenstrat :: (MonadSafe m) => FilePath
-> FilePath
-> FilePath
-> m ([EigenstratIndEntry], Producer (EigenstratSnpEntry, GenoLine) m ())
readEigenstrat :: forall (m :: * -> *).
MonadSafe m =>
String
-> String
-> String
-> m ([EigenstratIndEntry],
Producer (EigenstratSnpEntry, GenoLine) m ())
readEigenstrat String
genoFile String
snpFile String
indFile = do
[EigenstratIndEntry]
indEntries <- forall (m :: * -> *). MonadIO m => String -> m [EigenstratIndEntry]
readEigenstratInd String
indFile
let snpProd :: Producer EigenstratSnpEntry m ()
snpProd = forall (m :: * -> *).
MonadSafe m =>
String -> Producer EigenstratSnpEntry m ()
readEigenstratSnpFile String
snpFile
genoProd :: Proxy X () () GenoLine m ()
genoProd = forall (m :: * -> *) a.
MonadThrow m =>
Parser a -> Producer ByteString m () -> Producer a m ()
consumeProducer Parser GenoLine
eigenstratGenoParser (forall (m :: * -> *).
MonadSafe m =>
String -> Producer ByteString m ()
readFileProd String
genoFile) forall (m :: * -> *) a' a b r c' c.
Functor m =>
Proxy a' a () b m r -> Proxy () b c' c m r -> Proxy a' a c' c m r
>->
forall (m :: * -> *).
MonadThrow m =>
Int -> Pipe GenoLine GenoLine m ()
validateEigenstratEntries (forall (t :: * -> *) a. Foldable t => t a -> Int
length [EigenstratIndEntry]
indEntries)
forall (m :: * -> *) a. Monad m => a -> m a
return ([EigenstratIndEntry]
indEntries, forall (m :: * -> *) a r b x' x.
Monad m =>
Producer a m r -> Producer b m r -> Proxy x' x () (a, b) m r
P.zip Producer EigenstratSnpEntry m ()
snpProd Proxy X () () GenoLine m ()
genoProd)
validateEigenstratEntries :: (MonadThrow m) => Int -> Pipe GenoLine GenoLine m ()
validateEigenstratEntries :: forall (m :: * -> *).
MonadThrow m =>
Int -> Pipe GenoLine GenoLine m ()
validateEigenstratEntries Int
nr = forall (m :: * -> *) x' x b' b a' c' c.
Functor m =>
Proxy x' x b' b m a'
-> (b -> Proxy x' x c' c m b') -> Proxy x' x c' c m a'
for forall (m :: * -> *) a r. Functor m => Pipe a a m r
cat forall a b. (a -> b) -> a -> b
$ \GenoLine
line ->
if forall (t :: * -> *) a. Foldable t => t a -> Int
length GenoLine
line forall a. Eq a => a -> a -> Bool
/= Int
nr
then do
let msg :: String
msg = String
"inconsistent nr of genotypes (" forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> String
show (forall (t :: * -> *) a. Foldable t => t a -> Int
length GenoLine
line) forall a. Semigroup a => a -> a -> a
<> String
", but should be " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> String
show Int
nr forall a. Semigroup a => a -> a -> a
<> String
") in \
\genotype line " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> String
show GenoLine
line
forall a e. Exception e => e -> a
throw (String -> SeqFormatException
SeqFormatException String
msg)
else
forall (m :: * -> *) a x' x. Functor m => a -> Proxy x' x () a m ()
yield GenoLine
line
writeEigenstratIndFile :: (MonadIO m) => FilePath -> [EigenstratIndEntry] -> m ()
writeEigenstratIndFile :: forall (m :: * -> *).
MonadIO m =>
String -> [EigenstratIndEntry] -> m ()
writeEigenstratIndFile String
f [EigenstratIndEntry]
indEntries =
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall r. String -> IOMode -> (Handle -> IO r) -> IO r
withFile String
f IOMode
WriteMode forall a b. (a -> b) -> a -> b
$ \Handle
h ->
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [EigenstratIndEntry]
indEntries forall a b. (a -> b) -> a -> b
$ \(EigenstratIndEntry String
name Sex
sex String
popName) ->
Handle -> String -> IO ()
hPutStrLn Handle
h forall a b. (a -> b) -> a -> b
$ String
name forall a. Semigroup a => a -> a -> a
<> String
"\t" forall a. Semigroup a => a -> a -> a
<> forall {a}. IsString a => Sex -> a
sexToStr Sex
sex forall a. Semigroup a => a -> a -> a
<> String
"\t" forall a. Semigroup a => a -> a -> a
<> String
popName
where
sexToStr :: Sex -> a
sexToStr Sex
sex = case Sex
sex of
Sex
Male -> a
"M"
Sex
Female -> a
"F"
Sex
Unknown -> a
"U"
writeEigenstratSnp :: (MonadIO m) => Handle
-> Consumer EigenstratSnpEntry m ()
writeEigenstratSnp :: forall (m :: * -> *).
MonadIO m =>
Handle -> Consumer EigenstratSnpEntry m ()
writeEigenstratSnp Handle
snpFileH =
let snpOutTextConsumer :: Proxy () ByteString y' y m r
snpOutTextConsumer = forall (m :: * -> *) r.
MonadIO m =>
Handle -> Consumer' ByteString m r
PB.toHandle Handle
snpFileH
toTextPipe :: Pipe EigenstratSnpEntry ByteString m r
toTextPipe = forall (m :: * -> *) a b r. Functor m => (a -> b) -> Pipe a b m r
P.map (\(EigenstratSnpEntry Chrom
chrom Int
pos Double
gpos ByteString
gid Char
ref Char
alt) ->
let snpLine :: ByteString
snpLine = ByteString -> [ByteString] -> ByteString
B.intercalate ByteString
"\t" [ByteString
gid, Chrom -> ByteString
unChrom Chrom
chrom, String -> ByteString
B.pack (forall a. Show a => a -> String
show Double
gpos),
String -> ByteString
B.pack (forall a. Show a => a -> String
show Int
pos), Char -> ByteString
B.singleton Char
ref, Char -> ByteString
B.singleton Char
alt]
in ByteString
snpLine forall a. Semigroup a => a -> a -> a
<> ByteString
"\n")
in forall {r}. Pipe EigenstratSnpEntry ByteString m r
toTextPipe forall (m :: * -> *) a' a b r c' c.
Functor m =>
Proxy a' a () b m r -> Proxy () b c' c m r -> Proxy a' a c' c m r
>-> forall {y'} {y} {r}. Proxy () ByteString y' y m r
snpOutTextConsumer
writeEigenstratGeno :: (MonadIO m) => Handle
-> Consumer GenoLine m ()
writeEigenstratGeno :: forall (m :: * -> *). MonadIO m => Handle -> Consumer GenoLine m ()
writeEigenstratGeno Handle
genoFileH =
let genoOutTextConsumer :: Proxy () ByteString y' y m r
genoOutTextConsumer = forall (m :: * -> *) r.
MonadIO m =>
Handle -> Consumer' ByteString m r
PB.toHandle Handle
genoFileH
toTextPipe :: Pipe GenoLine ByteString m r
toTextPipe = forall (m :: * -> *) a b r. Functor m => (a -> b) -> Pipe a b m r
P.map (\GenoLine
genoLine ->
let genoLineStr :: ByteString
genoLineStr = [ByteString] -> ByteString
B.concat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (String -> ByteString
B.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show forall b c a. (b -> c) -> (a -> b) -> a -> c
. GenoEntry -> Int
toEigenStratNum) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Vector a -> [a]
toList forall a b. (a -> b) -> a -> b
$ GenoLine
genoLine
in ByteString
genoLineStr forall a. Semigroup a => a -> a -> a
<> ByteString
"\n")
in forall {r}. Pipe GenoLine ByteString m r
toTextPipe forall (m :: * -> *) a' a b r c' c.
Functor m =>
Proxy a' a () b m r -> Proxy () b c' c m r -> Proxy a' a c' c m r
>-> forall {y'} {y} {r}. Proxy () ByteString y' y m r
genoOutTextConsumer
where
toEigenStratNum :: GenoEntry -> Int
toEigenStratNum GenoEntry
c = case GenoEntry
c of
GenoEntry
HomRef -> Int
2 :: Int
GenoEntry
Het -> Int
1
GenoEntry
HomAlt -> Int
0
GenoEntry
Missing -> Int
9
writeEigenstrat :: (MonadSafe m) => FilePath
-> FilePath
-> FilePath
-> [EigenstratIndEntry]
-> Consumer (EigenstratSnpEntry, GenoLine) m ()
writeEigenstrat :: forall (m :: * -> *).
MonadSafe m =>
String
-> String
-> String
-> [EigenstratIndEntry]
-> Consumer (EigenstratSnpEntry, GenoLine) m ()
writeEigenstrat String
genoFile String
snpFile String
indFile [EigenstratIndEntry]
indEntries = do
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *).
MonadIO m =>
String -> [EigenstratIndEntry] -> m ()
writeEigenstratIndFile String
indFile [EigenstratIndEntry]
indEntries
let snpOutConsumer :: Proxy () EigenstratSnpEntry () X m ()
snpOutConsumer = forall (m :: * -> *) r.
MonadSafe m =>
String -> IOMode -> (Handle -> m r) -> m r
PS.withFile String
snpFile IOMode
WriteMode forall (m :: * -> *).
MonadIO m =>
Handle -> Consumer EigenstratSnpEntry m ()
writeEigenstratSnp
genoOutConsumer :: Proxy () GenoLine () X m ()
genoOutConsumer = forall (m :: * -> *) r.
MonadSafe m =>
String -> IOMode -> (Handle -> m r) -> m r
PS.withFile String
genoFile IOMode
WriteMode forall (m :: * -> *). MonadIO m => Handle -> Consumer GenoLine m ()
writeEigenstratGeno
forall (m :: * -> *) a r. Monad m => Consumer a m r -> Pipe a a m r
P.tee (forall (m :: * -> *) a b r. Functor m => (a -> b) -> Pipe a b m r
P.map forall a b. (a, b) -> a
fst forall (m :: * -> *) a' a b r c' c.
Functor m =>
Proxy a' a () b m r -> Proxy () b c' c m r -> Proxy a' a c' c m r
>-> Proxy () EigenstratSnpEntry () X m ()
snpOutConsumer) forall (m :: * -> *) a' a b r c' c.
Functor m =>
Proxy a' a () b m r -> Proxy () b c' c m r -> Proxy a' a c' c m r
>-> forall (m :: * -> *) a b r. Functor m => (a -> b) -> Pipe a b m r
P.map forall a b. (a, b) -> b
snd forall (m :: * -> *) a' a b r c' c.
Functor m =>
Proxy a' a () b m r -> Proxy () b c' c m r -> Proxy a' a c' c m r
>-> Proxy () GenoLine () X m ()
genoOutConsumer