module Sound.Audacity.LabelTrack where

import Text.Read.HT (maybeRead)
import Text.Printf (printf)

import Control.DeepSeq (NFData, rnf)
import Control.Monad (zipWithM)

import qualified Data.Traversable as Trav
import qualified Data.Foldable as Fold
import qualified Data.Monoid as Mn
import qualified Data.Semigroup as Sg
import qualified Data.List.NonEmpty as NonEmpty
import qualified Data.List.HT as ListHT
import Data.Tuple.HT (mapFst, mapSnd, mapPair)

import qualified Prelude as P
import Prelude hiding (readFile, writeFile, null)


newtype T time label = Cons {T time label -> [Interval time label]
decons :: [Interval time label]}

instance (Show time, Show label) => Show (T time label) where
   showsPrec :: Int -> T time label -> ShowS
showsPrec Int
p (Cons [Interval time label]
xs) =
      Bool -> ShowS -> ShowS
showParen (Int
pInt -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>Int
10) (ShowS -> ShowS) -> ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ String -> ShowS
showString String
"LabelTrack.Cons " ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Interval time label] -> ShowS
forall a. Show a => a -> ShowS
shows [Interval time label]
xs


type Interval time label = ((time, time), label)


instance Functor (T time) where
   fmap :: (a -> b) -> T time a -> T time b
fmap a -> b
f = ([Interval time a] -> [Interval time b]) -> T time a -> T time b
forall time0 label0 time1 label1.
([Interval time0 label0] -> [Interval time1 label1])
-> T time0 label0 -> T time1 label1
lift (([Interval time a] -> [Interval time b]) -> T time a -> T time b)
-> ([Interval time a] -> [Interval time b]) -> T time a -> T time b
forall a b. (a -> b) -> a -> b
$ (Interval time a -> Interval time b)
-> [Interval time a] -> [Interval time b]
forall a b. (a -> b) -> [a] -> [b]
map ((a -> b) -> Interval time a -> Interval time b
forall b c a. (b -> c) -> (a, b) -> (a, c)
mapSnd a -> b
f)

instance Fold.Foldable (T time) where
   foldMap :: (a -> m) -> T time a -> m
foldMap a -> m
f = (((time, time), a) -> m) -> [((time, time), a)] -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
Fold.foldMap (a -> m
f (a -> m) -> (((time, time), a) -> a) -> ((time, time), a) -> m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((time, time), a) -> a
forall a b. (a, b) -> b
snd) ([((time, time), a)] -> m)
-> (T time a -> [((time, time), a)]) -> T time a -> m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. T time a -> [((time, time), a)]
forall time label. T time label -> [Interval time label]
decons

instance Trav.Traversable (T time) where
   sequenceA :: T time (f a) -> f (T time a)
sequenceA =
      ([Interval time a] -> T time a)
-> f [Interval time a] -> f (T time a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Interval time a] -> T time a
forall time label. [Interval time label] -> T time label
Cons (f [Interval time a] -> f (T time a))
-> (T time (f a) -> f [Interval time a])
-> T time (f a)
-> f (T time a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (((time, time), f a) -> f (Interval time a))
-> [((time, time), f a)] -> f [Interval time a]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
Trav.traverse (\((time, time)
bnd, f a
label) -> (a -> Interval time a) -> f a -> f (Interval time a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((,) (time, time)
bnd) f a
label) ([((time, time), f a)] -> f [Interval time a])
-> (T time (f a) -> [((time, time), f a)])
-> T time (f a)
-> f [Interval time a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. T time (f a) -> [((time, time), f a)]
forall time label. T time label -> [Interval time label]
decons

instance Sg.Semigroup (T time label) where
   Cons [Interval time label]
xs <> :: T time label -> T time label -> T time label
<> Cons [Interval time label]
ys = [Interval time label] -> T time label
forall time label. [Interval time label] -> T time label
Cons ([Interval time label] -> T time label)
-> [Interval time label] -> T time label
forall a b. (a -> b) -> a -> b
$ [Interval time label]
xs [Interval time label]
-> [Interval time label] -> [Interval time label]
forall a. [a] -> [a] -> [a]
++ [Interval time label]
ys
   sconcat :: NonEmpty (T time label) -> T time label
sconcat = [Interval time label] -> T time label
forall time label. [Interval time label] -> T time label
Cons ([Interval time label] -> T time label)
-> (NonEmpty (T time label) -> [Interval time label])
-> NonEmpty (T time label)
-> T time label
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (T time label -> [Interval time label])
-> [T time label] -> [Interval time label]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap T time label -> [Interval time label]
forall time label. T time label -> [Interval time label]
decons ([T time label] -> [Interval time label])
-> (NonEmpty (T time label) -> [T time label])
-> NonEmpty (T time label)
-> [Interval time label]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty (T time label) -> [T time label]
forall a. NonEmpty a -> [a]
NonEmpty.toList

instance Mn.Monoid (T time label) where
   mempty :: T time label
mempty = T time label
forall time label. T time label
empty
   mappend :: T time label -> T time label -> T time label
mappend (Cons [Interval time label]
xs) (Cons [Interval time label]
ys) = [Interval time label] -> T time label
forall time label. [Interval time label] -> T time label
Cons ([Interval time label] -> T time label)
-> [Interval time label] -> T time label
forall a b. (a -> b) -> a -> b
$ [Interval time label]
xs [Interval time label]
-> [Interval time label] -> [Interval time label]
forall a. [a] -> [a] -> [a]
++ [Interval time label]
ys
   mconcat :: [T time label] -> T time label
mconcat = [Interval time label] -> T time label
forall time label. [Interval time label] -> T time label
Cons ([Interval time label] -> T time label)
-> ([T time label] -> [Interval time label])
-> [T time label]
-> T time label
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (T time label -> [Interval time label])
-> [T time label] -> [Interval time label]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap T time label -> [Interval time label]
forall time label. T time label -> [Interval time label]
decons

instance (NFData time, NFData label) => NFData (T time label) where
   rnf :: T time label -> ()
rnf = [Interval time label] -> ()
forall a. NFData a => a -> ()
rnf ([Interval time label] -> ())
-> (T time label -> [Interval time label]) -> T time label -> ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. T time label -> [Interval time label]
forall time label. T time label -> [Interval time label]
decons


empty :: T time label
empty :: T time label
empty = [Interval time label] -> T time label
forall time label. [Interval time label] -> T time label
Cons []

null :: T time label -> Bool
null :: T time label -> Bool
null = [Interval time label] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
P.null ([Interval time label] -> Bool)
-> (T time label -> [Interval time label]) -> T time label -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. T time label -> [Interval time label]
forall time label. T time label -> [Interval time label]
decons

singleton :: (time,time) -> label -> T time label
singleton :: (time, time) -> label -> T time label
singleton (time, time)
bnds label
label = [Interval time label] -> T time label
forall time label. [Interval time label] -> T time label
Cons [((time, time)
bnds, label
label)]


fromAdjacentChunks ::
   (Num time) => [(time, label)] -> T time label
fromAdjacentChunks :: [(time, label)] -> T time label
fromAdjacentChunks =
   [Interval time label] -> T time label
forall time label. [Interval time label] -> T time label
Cons ([Interval time label] -> T time label)
-> ([(time, label)] -> [Interval time label])
-> [(time, label)]
-> T time label
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (time, [Interval time label]) -> [Interval time label]
forall a b. (a, b) -> b
snd ((time, [Interval time label]) -> [Interval time label])
-> ([(time, label)] -> (time, [Interval time label]))
-> [(time, label)]
-> [Interval time label]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
   (time -> (time, label) -> (time, Interval time label))
-> time -> [(time, label)] -> (time, [Interval time label])
forall (t :: * -> *) a b c.
Traversable t =>
(a -> b -> (a, c)) -> a -> t b -> (a, t c)
Trav.mapAccumL (\time
t0 (time
d, label
lab) -> let t1 :: time
t1=time
t0time -> time -> time
forall a. Num a => a -> a -> a
+time
d in (time
t1, ((time
t0,time
t1), label
lab))) time
0


lift ::
   ([Interval time0 label0] -> [Interval time1 label1]) ->
   T time0 label0 -> T time1 label1
lift :: ([Interval time0 label0] -> [Interval time1 label1])
-> T time0 label0 -> T time1 label1
lift [Interval time0 label0] -> [Interval time1 label1]
f (Cons [Interval time0 label0]
xs) = [Interval time1 label1] -> T time1 label1
forall time label. [Interval time label] -> T time label
Cons ([Interval time1 label1] -> T time1 label1)
-> [Interval time1 label1] -> T time1 label1
forall a b. (a -> b) -> a -> b
$ [Interval time0 label0] -> [Interval time1 label1]
f [Interval time0 label0]
xs

lift2 ::
   ([Interval time0 label0] -> [Interval time1 label1] -> [Interval time2 label2]) ->
   T time0 label0 -> T time1 label1 -> T time2 label2
lift2 :: ([Interval time0 label0]
 -> [Interval time1 label1] -> [Interval time2 label2])
-> T time0 label0 -> T time1 label1 -> T time2 label2
lift2 [Interval time0 label0]
-> [Interval time1 label1] -> [Interval time2 label2]
f (Cons [Interval time0 label0]
xs) (Cons [Interval time1 label1]
ys) = [Interval time2 label2] -> T time2 label2
forall time label. [Interval time label] -> T time label
Cons ([Interval time2 label2] -> T time2 label2)
-> [Interval time2 label2] -> T time2 label2
forall a b. (a -> b) -> a -> b
$ [Interval time0 label0]
-> [Interval time1 label1] -> [Interval time2 label2]
f [Interval time0 label0]
xs [Interval time1 label1]
ys

{- |
Format the times using a comma,
which is certainly only correct in German locale.
-}
{-
ToDo: find out, how Audacity formats the labels.
In the project XML file format, the numbers are formatted with decimal points.
-}
formatTime :: (RealFrac time) => time -> String
formatTime :: time -> String
formatTime time
t =
   let million :: Integer
million = Integer
10Integer -> Int -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^(Int
6::Int)
       (Integer
seconds,Integer
micros) = Integer -> Integer -> (Integer, Integer)
forall a. Integral a => a -> a -> (a, a)
divMod (time -> Integer
forall a b. (RealFrac a, Integral b) => a -> b
round (time
t time -> time -> time
forall a. Num a => a -> a -> a
* Integer -> time
forall a. Num a => Integer -> a
fromInteger Integer
million)) Integer
million
   in  String -> Integer -> Integer -> String
forall r. PrintfType r => String -> r
printf String
"%d,%06d" Integer
seconds Integer
micros

{- |
You must make sure, that the time mapping function preserves the order.
This is not checked.
-}
mapTime :: (time0 -> time1) -> T time0 label -> T time1 label
mapTime :: (time0 -> time1) -> T time0 label -> T time1 label
mapTime time0 -> time1
f  =  ([Interval time0 label] -> [Interval time1 label])
-> T time0 label -> T time1 label
forall time0 label0 time1 label1.
([Interval time0 label0] -> [Interval time1 label1])
-> T time0 label0 -> T time1 label1
lift (([Interval time0 label] -> [Interval time1 label])
 -> T time0 label -> T time1 label)
-> ([Interval time0 label] -> [Interval time1 label])
-> T time0 label
-> T time1 label
forall a b. (a -> b) -> a -> b
$ (Interval time0 label -> Interval time1 label)
-> [Interval time0 label] -> [Interval time1 label]
forall a b. (a -> b) -> [a] -> [b]
map (((time0, time0) -> (time1, time1))
-> Interval time0 label -> Interval time1 label
forall a c b. (a -> c) -> (a, b) -> (c, b)
mapFst (((time0, time0) -> (time1, time1))
 -> Interval time0 label -> Interval time1 label)
-> ((time0, time0) -> (time1, time1))
-> Interval time0 label
-> Interval time1 label
forall a b. (a -> b) -> a -> b
$ (time0 -> time1, time0 -> time1)
-> (time0, time0) -> (time1, time1)
forall a c b d. (a -> c, b -> d) -> (a, b) -> (c, d)
mapPair (time0 -> time1
f, time0 -> time1
f))

mapWithTime ::
   ((time, time) -> label0 -> label1) -> T time label0 -> T time label1
mapWithTime :: ((time, time) -> label0 -> label1)
-> T time label0 -> T time label1
mapWithTime (time, time) -> label0 -> label1
f  =  ([Interval time label0] -> [Interval time label1])
-> T time label0 -> T time label1
forall time0 label0 time1 label1.
([Interval time0 label0] -> [Interval time1 label1])
-> T time0 label0 -> T time1 label1
lift (([Interval time label0] -> [Interval time label1])
 -> T time label0 -> T time label1)
-> ([Interval time label0] -> [Interval time label1])
-> T time label0
-> T time label1
forall a b. (a -> b) -> a -> b
$ (Interval time label0 -> Interval time label1)
-> [Interval time label0] -> [Interval time label1]
forall a b. (a -> b) -> [a] -> [b]
map (\((time, time)
bnd, label0
lab) -> ((time, time)
bnd, (time, time) -> label0 -> label1
f (time, time)
bnd label0
lab))

realTimes ::
   (Fractional time) =>
   time -> T Int label -> T time label
realTimes :: time -> T Int label -> T time label
realTimes time
sampleRate =
   (Int -> time) -> T Int label -> T time label
forall time0 time1 label.
(time0 -> time1) -> T time0 label -> T time1 label
mapTime (\Int
t -> Int -> time
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
t time -> time -> time
forall a. Fractional a => a -> a -> a
/ time
sampleRate)

mask :: (Ord time) => (time, time) -> T time label -> T time label
mask :: (time, time) -> T time label -> T time label
mask (time
from,time
to) =
   ([Interval time label] -> [Interval time label])
-> T time label -> T time label
forall time0 label0 time1 label1.
([Interval time0 label0] -> [Interval time1 label1])
-> T time0 label0 -> T time1 label1
lift (([Interval time label] -> [Interval time label])
 -> T time label -> T time label)
-> ([Interval time label] -> [Interval time label])
-> T time label
-> T time label
forall a b. (a -> b) -> a -> b
$
      (Interval time label -> Bool)
-> [Interval time label] -> [Interval time label]
forall a. (a -> Bool) -> [a] -> [a]
filter ((time -> time -> Bool) -> (time, time) -> Bool
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry time -> time -> Bool
forall a. Ord a => a -> a -> Bool
(<) ((time, time) -> Bool)
-> (Interval time label -> (time, time))
-> Interval time label
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Interval time label -> (time, time)
forall a b. (a, b) -> a
fst) ([Interval time label] -> [Interval time label])
-> ([Interval time label] -> [Interval time label])
-> [Interval time label]
-> [Interval time label]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
      (Interval time label -> Interval time label)
-> [Interval time label] -> [Interval time label]
forall a b. (a -> b) -> [a] -> [b]
map (((time, time) -> (time, time))
-> Interval time label -> Interval time label
forall a c b. (a -> c) -> (a, b) -> (c, b)
mapFst ((time -> time, time -> time) -> (time, time) -> (time, time)
forall a c b d. (a -> c, b -> d) -> (a, b) -> (c, d)
mapPair (time -> time -> time
forall a. Ord a => a -> a -> a
max time
from, time -> time -> time
forall a. Ord a => a -> a -> a
min time
to)))


zipWithList ::
   (label0 -> label1 -> label2) -> [label0] -> T time label1 -> T time label2
zipWithList :: (label0 -> label1 -> label2)
-> [label0] -> T time label1 -> T time label2
zipWithList label0 -> label1 -> label2
f [label0]
xs = ([Interval time label1] -> [Interval time label2])
-> T time label1 -> T time label2
forall time0 label0 time1 label1.
([Interval time0 label0] -> [Interval time1 label1])
-> T time0 label0 -> T time1 label1
lift (([Interval time label1] -> [Interval time label2])
 -> T time label1 -> T time label2)
-> ([Interval time label1] -> [Interval time label2])
-> T time label1
-> T time label2
forall a b. (a -> b) -> a -> b
$ (label0 -> Interval time label1 -> Interval time label2)
-> [label0] -> [Interval time label1] -> [Interval time label2]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (\label0
x ((time, time)
bnd, label1
y) -> ((time, time)
bnd, label0 -> label1 -> label2
f label0
x label1
y)) [label0]
xs


writeFile :: (RealFrac time) => FilePath -> T time String -> IO ()
writeFile :: String -> T time String -> IO ()
writeFile String
path T time String
intervals =
   String -> String -> IO ()
P.writeFile String
path (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$
   ((Interval String String -> String)
 -> [Interval String String] -> [String])
-> [Interval String String]
-> (Interval String String -> String)
-> [String]
forall a b c. (a -> b -> c) -> b -> a -> c
flip (Interval String String -> String)
-> [Interval String String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (T String String -> [Interval String String]
forall time label. T time label -> [Interval time label]
decons (T String String -> [Interval String String])
-> T String String -> [Interval String String]
forall a b. (a -> b) -> a -> b
$ (time -> String) -> T time String -> T String String
forall time0 time1 label.
(time0 -> time1) -> T time0 label -> T time1 label
mapTime time -> String
forall time. RealFrac time => time -> String
formatTime T time String
intervals) ((Interval String String -> String) -> [String])
-> (Interval String String -> String) -> [String]
forall a b. (a -> b) -> a -> b
$ \((String
from,String
to),String
label) ->
      String -> String -> String -> ShowS
forall r. PrintfType r => String -> r
printf String
"%s\t%s\t%s" String
from String
to String
label

writeFileInt ::
   (RealFrac time) =>
   time -> FilePath -> T Int String -> IO ()
writeFileInt :: time -> String -> T Int String -> IO ()
writeFileInt time
sampleRate String
path =
   String -> T time String -> IO ()
forall time. RealFrac time => String -> T time String -> IO ()
writeFile String
path (T time String -> IO ())
-> (T Int String -> T time String) -> T Int String -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. time -> T Int String -> T time String
forall time label.
Fractional time =>
time -> T Int label -> T time label
realTimes time
sampleRate


parseTime :: (Fractional time) => String -> Maybe time
parseTime :: String -> Maybe time
parseTime String
str =
   case (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
break (Char
','Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==) String
str of
      (String
intStr, Char
',':String
fracStr) -> do
         Integer
int <- String -> Maybe Integer
forall a. Read a => String -> Maybe a
maybeRead String
intStr
         Integer
frac <- String -> Maybe Integer
forall a. Read a => String -> Maybe a
maybeRead String
fracStr
         time -> Maybe time
forall (m :: * -> *) a. Monad m => a -> m a
return (time -> Maybe time) -> time -> Maybe time
forall a b. (a -> b) -> a -> b
$
            Integer -> time
forall a. Num a => Integer -> a
fromInteger Integer
int time -> time -> time
forall a. Num a => a -> a -> a
+
            Integer -> time
forall a. Num a => Integer -> a
fromInteger Integer
frac time -> time -> time
forall a. Fractional a => a -> a -> a
/ Integer -> time
forall a. Num a => Integer -> a
fromInteger (Integer
10 Integer -> Int -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
fracStr)
      (String
intStr, []) -> (Integer -> time) -> Maybe Integer -> Maybe time
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Integer -> time
forall a. Num a => Integer -> a
fromInteger (Maybe Integer -> Maybe time) -> Maybe Integer -> Maybe time
forall a b. (a -> b) -> a -> b
$ String -> Maybe Integer
forall a. Read a => String -> Maybe a
maybeRead String
intStr
      (String
_, Char
_:String
_) -> String -> Maybe time
forall a. HasCallStack => String -> a
error String
"break seems to match other characters than comma"

{- |
Read label file in a strict way.
-}
readFile :: (Fractional time) => FilePath -> IO (T time String)
readFile :: String -> IO (T time String)
readFile String
name =
   let parseTimeIO :: t -> String -> IO a
parseTimeIO t
n String
str =
          case String -> Maybe a
forall time. Fractional time => String -> Maybe time
parseTime String
str of
             Just a
t -> a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
t
             Maybe a
Nothing ->
                IOError -> IO a
forall a. IOError -> IO a
ioError (IOError -> IO a) -> IOError -> IO a
forall a b. (a -> b) -> a -> b
$ String -> IOError
userError (String -> IOError) -> String -> IOError
forall a b. (a -> b) -> a -> b
$
                String -> String -> t -> ShowS
forall r. PrintfType r => String -> r
printf String
"%s:%d: \"%s\" is not a number" String
name t
n String
str
       parseLine :: t -> String -> IO ((a, b), String)
parseLine t
n String
ln =
          case (Char -> Bool) -> String -> [String]
forall a. (a -> Bool) -> [a] -> [[a]]
ListHT.chop (Char
'\t'Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==) String
ln of
             [String
fromStr, String
toStr, String
label] -> do
                a
from <- t -> String -> IO a
forall a t. (Fractional a, PrintfArg t) => t -> String -> IO a
parseTimeIO t
n String
fromStr
                b
to <- t -> String -> IO b
forall a t. (Fractional a, PrintfArg t) => t -> String -> IO a
parseTimeIO t
n String
toStr
                ((a, b), String) -> IO ((a, b), String)
forall (m :: * -> *) a. Monad m => a -> m a
return ((a
from, b
to), String
label)
             [String]
fields ->
                IOError -> IO ((a, b), String)
forall a. IOError -> IO a
ioError (IOError -> IO ((a, b), String)) -> IOError -> IO ((a, b), String)
forall a b. (a -> b) -> a -> b
$ String -> IOError
userError (String -> IOError) -> String -> IOError
forall a b. (a -> b) -> a -> b
$
                String -> String -> t -> Int -> String
forall r. PrintfType r => String -> r
printf String
"%s:%d: expected 3 fields, but got %d"
                   String
name t
n ([String] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [String]
fields)
   in  ([Interval time String] -> T time String)
-> IO [Interval time String] -> IO (T time String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Interval time String] -> T time String
forall time label. [Interval time label] -> T time label
Cons (IO [Interval time String] -> IO (T time String))
-> IO [Interval time String] -> IO (T time String)
forall a b. (a -> b) -> a -> b
$ (Int -> String -> IO (Interval time String))
-> [Int] -> [String] -> IO [Interval time String]
forall (m :: * -> *) a b c.
Applicative m =>
(a -> b -> m c) -> [a] -> [b] -> m [c]
zipWithM Int -> String -> IO (Interval time String)
forall t a b.
(PrintfArg t, Fractional a, Fractional b) =>
t -> String -> IO ((a, b), String)
parseLine [Int
1::Int ..] ([String] -> IO [Interval time String])
-> (String -> [String]) -> String -> IO [Interval time String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines (String -> IO [Interval time String])
-> IO String -> IO [Interval time String]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< String -> IO String
P.readFile String
name