module Sound.Tidal.Utils where

import Data.List (delete)
import System.IO (hPutStrLn, stderr)

writeError :: String -> IO ()
writeError :: String -> IO ()
writeError = Handle -> String -> IO ()
hPutStrLn Handle
stderr

mapBoth :: (a -> a) -> (a,a) -> (a,a)
mapBoth :: (a -> a) -> (a, a) -> (a, a)
mapBoth f :: a -> a
f (a :: a
a,b :: a
b) = (a -> a
f a
a, a -> a
f a
b)

mapPartTimes :: (a -> a) -> ((a,a),(a,a)) -> ((a,a),(a,a))
mapPartTimes :: (a -> a) -> ((a, a), (a, a)) -> ((a, a), (a, a))
mapPartTimes f :: a -> a
f = ((a, a) -> (a, a)) -> ((a, a), (a, a)) -> ((a, a), (a, a))
forall a. (a -> a) -> (a, a) -> (a, a)
mapBoth ((a -> a) -> (a, a) -> (a, a)
forall a. (a -> a) -> (a, a) -> (a, a)
mapBoth a -> a
f)

mapFst :: (a -> b) -> (a, c) -> (b, c)
mapFst :: (a -> b) -> (a, c) -> (b, c)
mapFst f :: a -> b
f (x :: a
x,y :: c
y) = (a -> b
f a
x,c
y)

mapSnd :: (a -> b) -> (c, a) -> (c, b)
mapSnd :: (a -> b) -> (c, a) -> (c, b)
mapSnd f :: a -> b
f (x :: c
x,y :: a
y) = (c
x,a -> b
f a
y)

delta :: Num a => (a, a) -> a
delta :: (a, a) -> a
delta (a :: a
a,b :: a
b) = a
ba -> a -> a
forall a. Num a => a -> a -> a
-a
a

-- | The midpoint of two values
mid :: Fractional a => (a,a) -> a
mid :: (a, a) -> a
mid (a :: a
a,b :: a
b) = a
a a -> a -> a
forall a. Num a => a -> a -> a
+ ((a
b a -> a -> a
forall a. Num a => a -> a -> a
- a
a) a -> a -> a
forall a. Fractional a => a -> a -> a
/ 2)

removeCommon :: Eq a => [a] -> [a] -> ([a],[a])
removeCommon :: [a] -> [a] -> ([a], [a])
removeCommon [] bs :: [a]
bs = ([],[a]
bs)
removeCommon as :: [a]
as [] = ([a]
as,[])
removeCommon (a :: a
a:as :: [a]
as) bs :: [a]
bs | a
a a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [a]
bs = [a] -> [a] -> ([a], [a])
forall a. Eq a => [a] -> [a] -> ([a], [a])
removeCommon [a]
as (a -> [a] -> [a]
forall a. Eq a => a -> [a] -> [a]
delete a
a [a]
bs)
                       | Bool
otherwise = (a
aa -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
as',[a]
bs')
                      where (as' :: [a]
as',bs' :: [a]
bs') = [a] -> [a] -> ([a], [a])
forall a. Eq a => [a] -> [a] -> ([a], [a])
removeCommon [a]
as [a]
bs

readMaybe :: (Read a) => String -> Maybe a
readMaybe :: String -> Maybe a
readMaybe s :: String
s = case [a
x | (x :: a
x,t :: String
t) <- ReadS a
forall a. Read a => ReadS a
reads String
s, ("","") <- ReadS String
lex String
t] of
                   [x :: a
x] -> a -> Maybe a
forall a. a -> Maybe a
Just a
x
                   _   -> Maybe a
forall a. Maybe a
Nothing

{- | like `!!` selects @n@th element from xs, but wraps over at the end of @xs@

>>> map ((!!!) [1,3,5]) [0,1,2,3,4,5]
[1,3,5,1,3,5]
-}
(!!!) :: [a] -> Int -> a
!!! :: [a] -> Int -> a
(!!!) xs :: [a]
xs n :: Int
n = [a]
xs [a] -> Int -> a
forall a. [a] -> Int -> a
!! (Int
n Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
xs)


{- | Safer version of !! --}
nth :: Int -> [a] -> Maybe a
nth :: Int -> [a] -> Maybe a
nth _ []       = Maybe a
forall a. Maybe a
Nothing
nth 0 (x :: a
x : _)  = a -> Maybe a
forall a. a -> Maybe a
Just a
x
nth n :: Int
n (_ : xs :: [a]
xs) = Int -> [a] -> Maybe a
forall a. Int -> [a] -> Maybe a
nth (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- 1) [a]
xs

accumulate :: Num t => [t] -> [t]
accumulate :: [t] -> [t]
accumulate [] = []
accumulate (x :: t
x:xs :: [t]
xs) = (t -> t -> t) -> t -> [t] -> [t]
forall b a. (b -> a -> b) -> b -> [a] -> [b]
scanl t -> t -> t
forall a. Num a => a -> a -> a
(+) t
x [t]
xs

{- | enumerate a list of things

>>> enumerate ["foo","bar","baz"]
[(1,"foo"), (2,"bar"), (3,"baz")]
-}
enumerate :: [a] -> [(Int, a)]
enumerate :: [a] -> [(Int, a)]
enumerate = [Int] -> [a] -> [(Int, a)]
forall a b. [a] -> [b] -> [(a, b)]
zip [0..]

{- | split given list of @a@ by given single a, e.g.

>>> wordsBy (== ':') "bd:3"
["bd", "3"]
-}
wordsBy :: (a -> Bool) -> [a] -> [[a]]
wordsBy :: (a -> Bool) -> [a] -> [[a]]
wordsBy p :: a -> Bool
p s :: [a]
s = case (a -> Bool) -> [a] -> [a]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile a -> Bool
p [a]
s of
   []      -> []
   s' :: a
s':rest :: [a]
rest -> (a
s'a -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
w) [a] -> [[a]] -> [[a]]
forall a. a -> [a] -> [a]
: (a -> Bool) -> [a] -> [[a]]
forall a. (a -> Bool) -> [a] -> [[a]]
wordsBy a -> Bool
p (Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
drop 1 [a]
s'')
          where (w :: [a]
w, s'' :: [a]
s'') = (a -> Bool) -> [a] -> ([a], [a])
forall a. (a -> Bool) -> [a] -> ([a], [a])
break a -> Bool
p [a]
rest

-- A hack to add to the source code context for mini-notation, so
-- events know where they are within a whole tidal pattern
deltaMini :: String -> String
deltaMini :: String -> String
deltaMini = Int -> Int -> String -> String
outside 0 0
  where outside :: Int -> Int -> String -> String
        outside :: Int -> Int -> String -> String
outside _ _ [] = []
        outside column :: Int
column line :: Int
line ('"':xs :: String
xs) = ("(deltaContext "
                                         String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
column
                                         String -> String -> String
forall a. [a] -> [a] -> [a]
++ " "
                                         String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
line
                                         String -> String -> String
forall a. [a] -> [a] -> [a]
++ " \""
                                         String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> Int -> String -> String
inside (Int
columnInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) Int
line String
xs
                                       )
        outside _ line :: Int
line ('\n':xs :: String
xs) = '\n'Char -> String -> String
forall a. a -> [a] -> [a]
:(Int -> Int -> String -> String
outside 0 (Int
lineInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) String
xs)
        outside column :: Int
column line :: Int
line (x :: Char
x:xs :: String
xs) = Char
xChar -> String -> String
forall a. a -> [a] -> [a]
:(Int -> Int -> String -> String
outside (Int
columnInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) Int
line String
xs)
        inside :: Int -> Int -> String -> String
        inside :: Int -> Int -> String -> String
inside _ _ [] = []
        inside column :: Int
column line :: Int
line ('"':xs :: String
xs) = '"'Char -> String -> String
forall a. a -> [a] -> [a]
:')'Char -> String -> String
forall a. a -> [a] -> [a]
:(Int -> Int -> String -> String
outside (Int
columnInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) Int
line String
xs)
        inside _ line :: Int
line ('\n':xs :: String
xs) = '\n'Char -> String -> String
forall a. a -> [a] -> [a]
:(Int -> Int -> String -> String
inside 0 (Int
lineInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) String
xs)
        inside column :: Int
column line :: Int
line (x :: Char
x:xs :: String
xs) = Char
xChar -> String -> String
forall a. a -> [a] -> [a]
:(Int -> Int -> String -> String
inside (Int
columnInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) Int
line String
xs)