{-# LANGUAGE OverloadedStrings #-}

{-| Module to parse and write freqSum files. The freqsum format is defined here:
<https://rarecoal-docs.readthedocs.io/en/latest/rarecoal-tools.html#vcf2freqsum>
-}

module SequenceFormats.FreqSum (readFreqSumStdIn, readFreqSumFile, FreqSumEntry(..),  
    FreqSumHeader(..), printFreqSumStdOut, printFreqSumFile, freqSumEntryToText) where

import SequenceFormats.Utils (consumeProducer, Chrom(..), readFileProd)

import Control.Applicative ((<|>))
import Control.Monad.Catch (MonadThrow, throwM)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.Trans.State.Strict (runStateT)
import qualified Data.Attoparsec.ByteString.Char8 as A
import Data.Char (isAlphaNum, isSpace)
import qualified Data.ByteString.Char8 as B
import Pipes (Producer, (>->), Consumer)
import Pipes.Attoparsec (parse, ParsingError(..))
import qualified Pipes.Prelude as P
import Pipes.Safe (MonadSafe)
import Pipes.Safe.Prelude (withFile)
import qualified Pipes.ByteString as PB
import Prelude hiding (putStr)
import System.IO (IOMode(..))

-- |A Datatype representing the Header
data FreqSumHeader = FreqSumHeader {
    FreqSumHeader -> [String]
fshNames :: [String], -- ^A list of individual or group names
    FreqSumHeader -> [Int]
fshCounts :: [Int] -- ^A list of haplotype counts per individual/group.
} deriving (FreqSumHeader -> FreqSumHeader -> Bool
(FreqSumHeader -> FreqSumHeader -> Bool)
-> (FreqSumHeader -> FreqSumHeader -> Bool) -> Eq FreqSumHeader
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: FreqSumHeader -> FreqSumHeader -> Bool
$c/= :: FreqSumHeader -> FreqSumHeader -> Bool
== :: FreqSumHeader -> FreqSumHeader -> Bool
$c== :: FreqSumHeader -> FreqSumHeader -> Bool
Eq, Int -> FreqSumHeader -> ShowS
[FreqSumHeader] -> ShowS
FreqSumHeader -> String
(Int -> FreqSumHeader -> ShowS)
-> (FreqSumHeader -> String)
-> ([FreqSumHeader] -> ShowS)
-> Show FreqSumHeader
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FreqSumHeader] -> ShowS
$cshowList :: [FreqSumHeader] -> ShowS
show :: FreqSumHeader -> String
$cshow :: FreqSumHeader -> String
showsPrec :: Int -> FreqSumHeader -> ShowS
$cshowsPrec :: Int -> FreqSumHeader -> ShowS
Show)

freqSumHeaderToText :: FreqSumHeader -> B.ByteString
freqSumHeaderToText :: FreqSumHeader -> ByteString
freqSumHeaderToText (FreqSumHeader [String]
names [Int]
nCounts) =
    ByteString
"#CHROM\tPOS\tREF\tALT\t" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString -> [ByteString] -> ByteString
B.intercalate ByteString
"\t" [ByteString]
tuples ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
"\n"
  where
    tuples :: [ByteString]
tuples = (String -> Int -> ByteString) -> [String] -> [Int] -> [ByteString]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (\String
n Int
c -> String -> ByteString
B.pack String
n ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
"(" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> String -> ByteString
B.pack (Int -> String
forall a. Show a => a -> String
show Int
c) ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
")") [String]
names [Int]
nCounts

-- |A Datatype to denote a single freqSum line
data FreqSumEntry = FreqSumEntry {
    FreqSumEntry -> Chrom
fsChrom  :: Chrom, -- ^The chromosome of the site
    FreqSumEntry -> Int
fsPos    :: Int, -- ^The position of the site
    FreqSumEntry -> Maybe ByteString
fsSnpId  :: Maybe B.ByteString, -- ^An optional parameter to take the snpId. This is not parsed from or printed to freqSum format but is used in internal conversions from Eigenstrat.
    FreqSumEntry -> Maybe Double
fsGeneticPos :: Maybe Double, -- ^An optional parameter to take the genetic pos. This is not parsed from or printed to freqSum format but is used in internal conversions from Eigenstrat.
    FreqSumEntry -> Char
fsRef    :: Char, -- ^The reference allele
    FreqSumEntry -> Char
fsAlt    :: Char, -- ^The alternative allele
    FreqSumEntry -> [Maybe Int]
fsCounts :: [Maybe Int] -- ^A list of allele counts in each group. Nothing denotes missing data.
} deriving (FreqSumEntry -> FreqSumEntry -> Bool
(FreqSumEntry -> FreqSumEntry -> Bool)
-> (FreqSumEntry -> FreqSumEntry -> Bool) -> Eq FreqSumEntry
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: FreqSumEntry -> FreqSumEntry -> Bool
$c/= :: FreqSumEntry -> FreqSumEntry -> Bool
== :: FreqSumEntry -> FreqSumEntry -> Bool
$c== :: FreqSumEntry -> FreqSumEntry -> Bool
Eq, Int -> FreqSumEntry -> ShowS
[FreqSumEntry] -> ShowS
FreqSumEntry -> String
(Int -> FreqSumEntry -> ShowS)
-> (FreqSumEntry -> String)
-> ([FreqSumEntry] -> ShowS)
-> Show FreqSumEntry
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FreqSumEntry] -> ShowS
$cshowList :: [FreqSumEntry] -> ShowS
show :: FreqSumEntry -> String
$cshow :: FreqSumEntry -> String
showsPrec :: Int -> FreqSumEntry -> ShowS
$cshowsPrec :: Int -> FreqSumEntry -> ShowS
Show)

-- |This function converts a single freqSum entry to a printable freqSum line.
freqSumEntryToText :: FreqSumEntry -> B.ByteString
freqSumEntryToText :: FreqSumEntry -> ByteString
freqSumEntryToText (FreqSumEntry Chrom
chrom Int
pos Maybe ByteString
_ Maybe Double
_ Char
ref Char
alt [Maybe Int]
maybeCounts) =
    ByteString -> [ByteString] -> ByteString
B.intercalate ByteString
"\t" [Chrom -> ByteString
unChrom Chrom
chrom, String -> ByteString
B.pack (Int -> String
forall a. Show a => a -> String
show Int
pos), Char -> ByteString
B.singleton Char
ref, Char -> ByteString
B.singleton Char
alt, ByteString
countStr] ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
"\n"
  where
    countStr :: ByteString
countStr = ByteString -> [ByteString] -> ByteString
B.intercalate ByteString
"\t" ([ByteString] -> ByteString)
-> ([Maybe Int] -> [ByteString]) -> [Maybe Int] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe Int -> ByteString) -> [Maybe Int] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map (String -> ByteString
B.pack (String -> ByteString)
-> (Maybe Int -> String) -> Maybe Int -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String
forall a. Show a => a -> String
show (Int -> String) -> (Maybe Int -> Int) -> Maybe Int -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe Int -> Int
forall p. Num p => Maybe p -> p
convertToNum) ([Maybe Int] -> ByteString) -> [Maybe Int] -> ByteString
forall a b. (a -> b) -> a -> b
$ [Maybe Int]
maybeCounts 
    convertToNum :: Maybe p -> p
convertToNum Maybe p
Nothing = -p
1
    convertToNum (Just p
a) = p
a

readFreqSumProd :: (MonadThrow m) =>
    Producer B.ByteString m () -> m (FreqSumHeader, Producer FreqSumEntry m ())
readFreqSumProd :: Producer ByteString m ()
-> m (FreqSumHeader, Producer FreqSumEntry m ())
readFreqSumProd Producer ByteString m ()
prod = do
    (Maybe (Either ParsingError FreqSumHeader)
res, Producer ByteString m ()
rest) <- StateT
  (Producer ByteString m ())
  m
  (Maybe (Either ParsingError FreqSumHeader))
-> Producer ByteString m ()
-> m (Maybe (Either ParsingError FreqSumHeader),
      Producer ByteString m ())
forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
runStateT (Parser ByteString FreqSumHeader
-> Parser ByteString m (Maybe (Either ParsingError FreqSumHeader))
forall (m :: * -> *) a b.
(Monad m, ParserInput a) =>
Parser a b -> Parser a m (Maybe (Either ParsingError b))
parse Parser ByteString FreqSumHeader
parseFreqSumHeader) Producer ByteString m ()
prod
    FreqSumHeader
header <- case Maybe (Either ParsingError FreqSumHeader)
res of
        Maybe (Either ParsingError FreqSumHeader)
Nothing -> ParsingError -> m FreqSumHeader
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (ParsingError -> m FreqSumHeader)
-> ParsingError -> m FreqSumHeader
forall a b. (a -> b) -> a -> b
$ [String] -> String -> ParsingError
ParsingError [] String
"freqSum file exhausted"
        Just (Left ParsingError
e) -> ParsingError -> m FreqSumHeader
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM ParsingError
e
        Just (Right FreqSumHeader
h) -> FreqSumHeader -> m FreqSumHeader
forall (m :: * -> *) a. Monad m => a -> m a
return FreqSumHeader
h
    (FreqSumHeader, Producer FreqSumEntry m ())
-> m (FreqSumHeader, Producer FreqSumEntry m ())
forall (m :: * -> *) a. Monad m => a -> m a
return (FreqSumHeader
header, Parser FreqSumEntry
-> Producer ByteString m () -> Producer FreqSumEntry m ()
forall (m :: * -> *) a.
MonadThrow m =>
Parser a -> Producer ByteString m () -> Producer a m ()
consumeProducer Parser FreqSumEntry
parseFreqSumEntry Producer ByteString m ()
rest)

-- |A function to read a freqsum file from StdIn. Returns a pair of a freqSum Header and a Producer over all lines.
readFreqSumStdIn :: (MonadIO m, MonadThrow m) => m (FreqSumHeader, Producer FreqSumEntry m ())
readFreqSumStdIn :: m (FreqSumHeader, Producer FreqSumEntry m ())
readFreqSumStdIn = Producer ByteString m ()
-> m (FreqSumHeader, Producer FreqSumEntry m ())
forall (m :: * -> *).
MonadThrow m =>
Producer ByteString m ()
-> m (FreqSumHeader, Producer FreqSumEntry m ())
readFreqSumProd Producer ByteString m ()
forall (m :: * -> *). MonadIO m => Producer' ByteString m ()
PB.stdin

-- |A function to read a freqsum file from a file. Returns a pair of a freqSum Header and a Producer over all lines.
readFreqSumFile :: (MonadSafe m) => FilePath -> m (FreqSumHeader, Producer FreqSumEntry m ())
readFreqSumFile :: String -> m (FreqSumHeader, Producer FreqSumEntry m ())
readFreqSumFile = Producer ByteString m ()
-> m (FreqSumHeader, Producer FreqSumEntry m ())
forall (m :: * -> *).
MonadThrow m =>
Producer ByteString m ()
-> m (FreqSumHeader, Producer FreqSumEntry m ())
readFreqSumProd (Producer ByteString m ()
 -> m (FreqSumHeader, Producer FreqSumEntry m ()))
-> (String -> Producer ByteString m ())
-> String
-> m (FreqSumHeader, Producer FreqSumEntry m ())
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Producer ByteString m ()
forall (m :: * -> *).
MonadSafe m =>
String -> Producer ByteString m ()
readFileProd

parseFreqSumHeader :: A.Parser FreqSumHeader
parseFreqSumHeader :: Parser ByteString FreqSumHeader
parseFreqSumHeader = do
    [(ByteString, Int)]
tuples <- ByteString -> Parser ByteString
A.string ByteString
"#CHROM\tPOS\tREF\tALT\t" Parser ByteString
-> Parser ByteString [(ByteString, Int)]
-> Parser ByteString [(ByteString, Int)]
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Parser ByteString (ByteString, Int)
-> Parser ByteString Char -> Parser ByteString [(ByteString, Int)]
forall (m :: * -> *) a s. MonadPlus m => m a -> m s -> m [a]
A.sepBy' Parser ByteString (ByteString, Int)
tuple Parser ByteString Char
A.space Parser ByteString [(ByteString, Int)]
-> Parser ByteString () -> Parser ByteString [(ByteString, Int)]
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser ByteString ()
A.endOfLine
    let names :: [ByteString]
names = ((ByteString, Int) -> ByteString)
-> [(ByteString, Int)] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map (ByteString, Int) -> ByteString
forall a b. (a, b) -> a
fst [(ByteString, Int)]
tuples
        counts :: [Int]
counts = ((ByteString, Int) -> Int) -> [(ByteString, Int)] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (ByteString, Int) -> Int
forall a b. (a, b) -> b
snd [(ByteString, Int)]
tuples
    FreqSumHeader -> Parser ByteString FreqSumHeader
forall (m :: * -> *) a. Monad m => a -> m a
return (FreqSumHeader -> Parser ByteString FreqSumHeader)
-> FreqSumHeader -> Parser ByteString FreqSumHeader
forall a b. (a -> b) -> a -> b
$ [String] -> [Int] -> FreqSumHeader
FreqSumHeader ((ByteString -> String) -> [ByteString] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ByteString -> String
B.unpack [ByteString]
names) [Int]
counts
  where
    tuple :: Parser ByteString (ByteString, Int)
tuple = (,) (ByteString -> Int -> (ByteString, Int))
-> Parser ByteString
-> Parser ByteString (Int -> (ByteString, Int))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Char -> Bool) -> Parser ByteString
A.takeWhile (\Char
c -> Char -> Bool
isAlphaNum Char
c Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'_' Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'-') Parser ByteString (Int -> (ByteString, Int))
-> Parser ByteString Char
-> Parser ByteString (Int -> (ByteString, Int))
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Char -> Parser ByteString Char
A.char Char
'(' Parser ByteString (Int -> (ByteString, Int))
-> Parser ByteString Int -> Parser ByteString (ByteString, Int)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser ByteString Int
forall a. Integral a => Parser a
A.decimal Parser ByteString (ByteString, Int)
-> Parser ByteString Char -> Parser ByteString (ByteString, Int)
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Char -> Parser ByteString Char
A.char Char
')'

parseFreqSumEntry :: A.Parser FreqSumEntry
parseFreqSumEntry :: Parser FreqSumEntry
parseFreqSumEntry = Chrom
-> Int
-> Maybe ByteString
-> Maybe Double
-> Char
-> Char
-> [Maybe Int]
-> FreqSumEntry
FreqSumEntry (Chrom
 -> Int
 -> Maybe ByteString
 -> Maybe Double
 -> Char
 -> Char
 -> [Maybe Int]
 -> FreqSumEntry)
-> Parser ByteString Chrom
-> Parser
     ByteString
     (Int
      -> Maybe ByteString
      -> Maybe Double
      -> Char
      -> Char
      -> [Maybe Int]
      -> FreqSumEntry)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (ByteString -> Chrom
Chrom (ByteString -> Chrom)
-> Parser ByteString -> Parser ByteString Chrom
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Char -> Bool) -> Parser ByteString
A.takeTill Char -> Bool
isSpace) Parser
  ByteString
  (Int
   -> Maybe ByteString
   -> Maybe Double
   -> Char
   -> Char
   -> [Maybe Int]
   -> FreqSumEntry)
-> Parser ByteString ()
-> Parser
     ByteString
     (Int
      -> Maybe ByteString
      -> Maybe Double
      -> Char
      -> Char
      -> [Maybe Int]
      -> FreqSumEntry)
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser ByteString ()
A.skipSpace Parser
  ByteString
  (Int
   -> Maybe ByteString
   -> Maybe Double
   -> Char
   -> Char
   -> [Maybe Int]
   -> FreqSumEntry)
-> Parser ByteString Int
-> Parser
     ByteString
     (Maybe ByteString
      -> Maybe Double -> Char -> Char -> [Maybe Int] -> FreqSumEntry)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser ByteString Int
forall a. Integral a => Parser a
A.decimal Parser
  ByteString
  (Maybe ByteString
   -> Maybe Double -> Char -> Char -> [Maybe Int] -> FreqSumEntry)
-> Parser ByteString ()
-> Parser
     ByteString
     (Maybe ByteString
      -> Maybe Double -> Char -> Char -> [Maybe Int] -> FreqSumEntry)
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<*
    Parser ByteString ()
A.skipSpace Parser
  ByteString
  (Maybe ByteString
   -> Maybe Double -> Char -> Char -> [Maybe Int] -> FreqSumEntry)
-> Parser ByteString (Maybe ByteString)
-> Parser
     ByteString
     (Maybe Double -> Char -> Char -> [Maybe Int] -> FreqSumEntry)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Maybe ByteString -> Parser ByteString (Maybe ByteString)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe ByteString
forall a. Maybe a
Nothing Parser
  ByteString
  (Maybe Double -> Char -> Char -> [Maybe Int] -> FreqSumEntry)
-> Parser ByteString (Maybe Double)
-> Parser ByteString (Char -> Char -> [Maybe Int] -> FreqSumEntry)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Maybe Double -> Parser ByteString (Maybe Double)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe Double
forall a. Maybe a
Nothing Parser ByteString (Char -> Char -> [Maybe Int] -> FreqSumEntry)
-> Parser ByteString Char
-> Parser ByteString (Char -> [Maybe Int] -> FreqSumEntry)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser ByteString Char
base Parser ByteString (Char -> [Maybe Int] -> FreqSumEntry)
-> Parser ByteString ()
-> Parser ByteString (Char -> [Maybe Int] -> FreqSumEntry)
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser ByteString ()
A.skipSpace Parser ByteString (Char -> [Maybe Int] -> FreqSumEntry)
-> Parser ByteString Char
-> Parser ByteString ([Maybe Int] -> FreqSumEntry)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser ByteString Char
baseOrDot Parser ByteString ([Maybe Int] -> FreqSumEntry)
-> Parser ByteString ()
-> Parser ByteString ([Maybe Int] -> FreqSumEntry)
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser ByteString ()
A.skipSpace Parser ByteString ([Maybe Int] -> FreqSumEntry)
-> Parser ByteString [Maybe Int] -> Parser FreqSumEntry
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser ByteString [Maybe Int]
counts Parser FreqSumEntry -> Parser ByteString () -> Parser FreqSumEntry
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser ByteString ()
A.endOfLine
  where
    counts :: Parser ByteString [Maybe Int]
counts = (Parser ByteString (Maybe Int)
forall a. Parser ByteString (Maybe a)
parseMissing Parser ByteString (Maybe Int)
-> Parser ByteString (Maybe Int) -> Parser ByteString (Maybe Int)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser ByteString (Maybe Int)
parseCount) Parser ByteString (Maybe Int)
-> Parser ByteString Char -> Parser ByteString [Maybe Int]
forall (f :: * -> *) a s. Alternative f => f a -> f s -> f [a]
`A.sepBy` Char -> Parser ByteString Char
A.char Char
'\t'
    parseMissing :: Parser ByteString (Maybe a)
parseMissing = ByteString -> Parser ByteString
A.string ByteString
"-1" Parser ByteString
-> Parser ByteString (Maybe a) -> Parser ByteString (Maybe a)
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Maybe a -> Parser ByteString (Maybe a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe a
forall a. Maybe a
Nothing
    parseCount :: Parser ByteString (Maybe Int)
parseCount = Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int)
-> Parser ByteString Int -> Parser ByteString (Maybe Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser ByteString Int
forall a. Integral a => Parser a
A.decimal
    base :: Parser ByteString Char
base = (Char -> Bool) -> Parser ByteString Char
A.satisfy (String -> Char -> Bool
A.inClass String
"ACTGN")
    baseOrDot :: Parser ByteString Char
baseOrDot = (Char -> Bool) -> Parser ByteString Char
A.satisfy (String -> Char -> Bool
A.inClass String
"ACTG.")

-- |A function to write freqSum data to StdOut. Expects the freqSum header as argument, and then returns a Consumer that accepts freqSum entries.
printFreqSumStdOut :: (MonadIO m) => FreqSumHeader -> Consumer FreqSumEntry m ()
printFreqSumStdOut :: FreqSumHeader -> Consumer FreqSumEntry m ()
printFreqSumStdOut FreqSumHeader
fsh = do
    IO () -> Consumer FreqSumEntry m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Consumer FreqSumEntry m ())
-> (FreqSumHeader -> IO ())
-> FreqSumHeader
-> Consumer FreqSumEntry m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> IO ()
B.putStr (ByteString -> IO ())
-> (FreqSumHeader -> ByteString) -> FreqSumHeader -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FreqSumHeader -> ByteString
freqSumHeaderToText (FreqSumHeader -> Consumer FreqSumEntry m ())
-> FreqSumHeader -> Consumer FreqSumEntry m ()
forall a b. (a -> b) -> a -> b
$ FreqSumHeader
fsh
    (FreqSumEntry -> ByteString) -> Pipe FreqSumEntry ByteString m ()
forall (m :: * -> *) a b r. Functor m => (a -> b) -> Pipe a b m r
P.map FreqSumEntry -> ByteString
freqSumEntryToText Pipe FreqSumEntry ByteString m ()
-> Proxy () ByteString () X m () -> Consumer FreqSumEntry m ()
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 () ByteString () X m ()
forall (m :: * -> *). MonadIO m => Consumer' ByteString m ()
PB.stdout

-- |A function that writes a freqSum file. Expects the FilePath and the freqSum header as arguments, and then returns a Consumer that accepts freqSum entries.
printFreqSumFile :: (MonadSafe m) => FilePath -> FreqSumHeader -> Consumer FreqSumEntry m ()
printFreqSumFile :: String -> FreqSumHeader -> Consumer FreqSumEntry m ()
printFreqSumFile String
outFile FreqSumHeader
fsh = String
-> IOMode
-> (Handle -> Consumer FreqSumEntry m ())
-> Consumer FreqSumEntry m ()
forall (m :: * -> *) r.
MonadSafe m =>
String -> IOMode -> (Handle -> m r) -> m r
withFile String
outFile IOMode
WriteMode Handle -> Consumer FreqSumEntry m ()
forall (m :: * -> *) c' c b.
MonadIO m =>
Handle -> Proxy () FreqSumEntry c' c m b
go
  where
    go :: Handle -> Proxy () FreqSumEntry c' c m b
go Handle
h = do
        IO () -> Proxy () FreqSumEntry c' c m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Proxy () FreqSumEntry c' c m ())
-> (FreqSumHeader -> IO ())
-> FreqSumHeader
-> Proxy () FreqSumEntry c' c m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> ByteString -> IO ()
B.hPutStr Handle
h (ByteString -> IO ())
-> (FreqSumHeader -> ByteString) -> FreqSumHeader -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FreqSumHeader -> ByteString
freqSumHeaderToText (FreqSumHeader -> Proxy () FreqSumEntry c' c m ())
-> FreqSumHeader -> Proxy () FreqSumEntry c' c m ()
forall a b. (a -> b) -> a -> b
$ FreqSumHeader
fsh
        (FreqSumEntry -> ByteString) -> Pipe FreqSumEntry ByteString m b
forall (m :: * -> *) a b r. Functor m => (a -> b) -> Pipe a b m r
P.map FreqSumEntry -> ByteString
freqSumEntryToText Pipe FreqSumEntry ByteString m b
-> Proxy () ByteString c' c m b -> Proxy () FreqSumEntry c' c m b
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
>-> Handle -> Consumer' ByteString m b
forall (m :: * -> *) r.
MonadIO m =>
Handle -> Consumer' ByteString m r
PB.toHandle Handle
h