module Music.Theory.List where
import Data.Either
import Data.Function
import qualified Data.IntMap as Map
import Data.List
import Data.Maybe
import Data.Tree
import qualified Data.Traversable as T
import qualified Data.List.Ordered as O
import qualified Data.List.Split as S
import qualified Data.List.Split.Internals as S
import qualified Control.Monad.Logic as L
slice :: Int -> Int -> [a] -> [a]
slice i n = take n . drop i
section :: Int -> Int -> [a] -> [a]
section l r = take (r l + 1) . drop l
bracket :: (a,a) -> [a] -> [a]
bracket (l,r) x = l : x ++ [r]
unbracket' :: [a] -> (Maybe a,[a],Maybe a)
unbracket' x =
case x of
[] -> (Nothing,[],Nothing)
l:x' -> let (m,r) = separate_last' x' in (Just l,m,r)
unbracket :: [t] -> Maybe (t,[t],t)
unbracket x =
case unbracket' x of
(Just l,m,Just r) -> Just (l,m,r)
_ -> Nothing
unbracket_err :: [t] -> (t,[t],t)
unbracket_err = fromMaybe (error "unbracket") . unbracket
bracket_l :: ([a],[a]) -> [a] -> [a]
bracket_l (l,r) s = l ++ s ++ r
separate_at :: Eq a => [a] -> [a] -> Maybe ([a],[a])
separate_at x =
let n = length x
f lhs rhs =
if null rhs
then Nothing
else if x == take n rhs
then Just (reverse lhs,drop n rhs)
else f (head rhs : lhs) (tail rhs)
in f []
on_elem :: Eq a => a -> S.Splitter a
on_elem e = S.defaultSplitter { S.delimiter = S.Delimiter [(==) e] }
split_before :: Eq a => a -> [a] -> [[a]]
split_before = S.split . S.keepDelimsL . on_elem
genericRotate_left :: Integral i => i -> [a] -> [a]
genericRotate_left n =
let f (p,q) = q ++ p
in f . genericSplitAt n
rotate_left :: Int -> [a] -> [a]
rotate_left = genericRotate_left
genericRotate_right :: Integral n => n -> [a] -> [a]
genericRotate_right n = reverse . genericRotate_left n . reverse
rotate_right :: Int -> [a] -> [a]
rotate_right = genericRotate_right
rotate :: (Integral n) => n -> [a] -> [a]
rotate n p =
let m = n `mod` genericLength p
in genericRotate_left m p
rotate_r :: (Integral n) => n -> [a] -> [a]
rotate_r = rotate . negate
rotations :: [a] -> [[a]]
rotations p = map (`rotate_left` p) [0 .. length p 1]
rotate_starting_from :: Eq a => a -> [a] -> Maybe [a]
rotate_starting_from x l =
case break (== x) l of
(_,[]) -> Nothing
(lhs,rhs) -> Just (rhs ++ lhs)
rotate_starting_from_err :: Eq a => a -> [a] -> [a]
rotate_starting_from_err x =
fromMaybe (error "rotate_starting_from: non-element") .
rotate_starting_from x
adj :: Int -> Int -> [a] -> [[a]]
adj n k l =
case take n l of
[] -> []
r -> r : adj n k (drop k l)
adj' :: Int -> Int -> [a] -> [[a]]
adj' n k l =
let r = take n l
in if length r == n then r : adj' n k (drop k l) else []
genericAdj2 :: (Integral n) => n -> [t] -> [(t,t)]
genericAdj2 n l =
case l of
p:q:_ -> (p,q) : genericAdj2 n (genericDrop n l)
_ -> []
adj2 :: Int -> [t] -> [(t,t)]
adj2 = genericAdj2
close :: [a] -> [a]
close x =
case x of
[] -> []
e:_ -> x ++ [e]
adj2_cyclic :: Int -> [t] -> [(t,t)]
adj2_cyclic n = adj2 n . close
interleave :: [a] -> [a] -> [a]
interleave p q =
let u (i,j) = [i,j]
in concatMap u (zip p q)
interleave_set :: [[a]] -> [a]
interleave_set = concat . transpose
deinterleave :: Int -> [a] -> [[a]]
deinterleave n = transpose . S.chunksOf n
deinterleave2 :: [t] -> ([t], [t])
deinterleave2 =
let f l =
case l of
p:q:l' -> (p,q) : f l'
_ -> []
in unzip . f
interleave_continue :: [a] -> [a] -> [a]
interleave_continue p q =
case (p,q) of
([],_) -> q
(_,[]) -> p
(i:p',j:q') -> i : j : interleave_continue p' q'
interleave_rotations :: Int -> Int -> [b] -> [b]
interleave_rotations i j s = interleave (rotate_left i s) (rotate_left j s)
generic_histogram :: (Ord a,Integral i) => [a] -> [(a,i)]
generic_histogram x =
let g = group (sort x)
in zip (map head g) (map genericLength g)
histogram_by :: Ord a => (a -> a -> Bool) -> [a] -> [(a,Int)]
histogram_by f x =
let g = groupBy f (sort x)
in zip (map head g) (map length g)
histogram :: Ord a => [a] -> [(a,Int)]
histogram = histogram_by (==)
duplicates_by :: Ord a => (a -> a -> Bool) -> [a] -> [a]
duplicates_by f = map fst . filter (\(_,n) -> n > 1) . histogram_by f
duplicates :: Ord a => [a] -> [a]
duplicates = duplicates_by (==)
segments :: Int -> Int -> [a] -> [[a]]
segments i j p =
let q = take i p
p' = drop j p
in if length q /= i then [] else q : segments i j p'
intersect_l :: Eq a => [[a]] -> [a]
intersect_l = foldl1 intersect
union_l :: Eq a => [[a]] -> [a]
union_l = foldl1 union
adj_intersect :: Eq a => Int -> [[a]] -> [[a]]
adj_intersect n = map intersect_l . segments 2 n
cycles :: Int -> [a] -> [[a]]
cycles n = transpose . S.chunksOf n
filter_halt :: (a -> Bool) -> (a -> Bool) -> [a] -> [a]
filter_halt sel end = filter sel . takeWhile end
replace :: Eq a => [a] -> [a] -> [a] -> [a]
replace p q s =
let n = length p
in case s of
[] -> []
c:s' -> if p `isPrefixOf` s
then q ++ replace p q (drop n s)
else c : replace p q s'
replace_at :: Integral i => [a] -> i -> a -> [a]
replace_at ns i x =
let f j y = if i == j then x else y
in zipWith f [0..] ns
group_on :: Eq x => (a -> x) -> [a] -> [[a]]
group_on f = map (map snd) . groupBy ((==) `on` fst) . map (\x -> (f x,x))
collate_on_adjacent :: (Eq k,Ord k) => (a -> k) -> (a -> v) -> [a] -> [(k,[v])]
collate_on_adjacent f g =
let h l = case l of
[] -> error "collate_on_adjacent"
l0:_ -> (f l0,map g l)
in map h . group_on f
collate_adjacent :: Ord a => [(a,b)] -> [(a,[b])]
collate_adjacent = collate_on_adjacent fst snd
collate_on :: Ord k => (a -> k) -> (a -> v) -> [a] -> [(k,[v])]
collate_on f g = collate_on_adjacent f g . sortOn f
collate :: Ord a => [(a,b)] -> [(a,[b])]
collate = collate_on fst snd
uncollate :: [(k,[v])] -> [(k,v)]
uncollate = concatMap (\(k,v) -> zip (repeat k) v)
with_key :: k -> [v] -> [(k,v)]
with_key h = zip (repeat h)
dx_d :: (Num a) => a -> [a] -> [a]
dx_d = scanl (+)
dx_d' :: Num t => t -> [t] -> (t,[t])
dx_d' n l =
case reverse (scanl (+) n l) of
e:r -> (e,reverse r)
_ -> error "dx_d'"
d_dx_by :: (t -> t -> u) -> [t] -> [u]
d_dx_by f l = if null l then [] else zipWith f (tail l) l
d_dx :: (Num a) => [a] -> [a]
d_dx = d_dx_by ()
difference :: (Eq a) => [a] -> [a] -> [a]
difference p q =
let f e = e `notElem` q
in filter f p
is_subset :: Eq a => [a] -> [a] -> Bool
is_subset p q = p `intersect` q == p
is_superset :: Eq a => [a] -> [a] -> Bool
is_superset = flip is_subset
subsequence :: (Eq a) => [a] -> [a] -> Bool
subsequence = isInfixOf
elem_index_unique :: (Eq a) => a -> [a] -> Int
elem_index_unique e p =
case elemIndices e p of
[i] -> i
_ -> error "elem_index_unique"
lookup_err_msg :: (Eq k,Show k) => String -> k -> [(k,v)] -> v
lookup_err_msg err k = fromMaybe (error (err ++ ": " ++ show k)) . lookup k
lookup_err :: Eq k => k -> [(k,v)] -> v
lookup_err n = fromMaybe (error "lookup") . lookup n
lookup_def :: Eq k => k -> v -> [(k,v)] -> v
lookup_def k d = fromMaybe d . lookup k
reverse_lookup :: Eq b => b -> [(a,b)] -> Maybe a
reverse_lookup k = fmap fst . find ((== k) . snd)
find_bounds' :: (t -> s -> Ordering) -> [(t,t)] -> s -> Either ((t,t),Ordering) (t,t)
find_bounds' f l x =
let g (p,q) = f p x /= GT && f q x == GT
in case l of
[] -> error "find_bounds': nil"
[(p,q)] -> if g (p,q) then Right (p,q) else Left ((p,q),f q x)
(p,q):l' -> if f p x == GT
then Left ((p,q),GT)
else if g (p,q) then Right (p,q) else find_bounds' f l' x
decide_nearest' :: Ord o => (p -> o) -> (p,p) -> p
decide_nearest' f (p,q) = if f p < f q then p else q
decide_nearest :: (Num o,Ord o) => o -> (o, o) -> o
decide_nearest x = decide_nearest' (abs . (x ))
find_nearest_err :: (Num n,Ord n) => [n] -> n -> n
find_nearest_err l x =
case find_bounds' compare (adj2 1 l) x of
Left ((p,_),GT) -> p
Left ((_,q),_) -> q
Right (p,q) -> decide_nearest x (p,q)
find_nearest :: (Num n,Ord n) => [n] -> n -> Maybe n
find_nearest l x = if null l then Nothing else Just (find_nearest_err l x)
find_bounds_scl :: Bool -> (t -> s -> Ordering) -> [(t,t)] -> s -> Maybe (t,t)
find_bounds_scl scl f l x =
case find_bounds' f l x of
Right r -> Just r
Left (r,EQ) -> if scl then Just r else Nothing
_ -> Nothing
find_bounds :: Bool -> (t -> s -> Ordering) -> [t] -> s -> Maybe (t,t)
find_bounds scl f l = find_bounds_scl scl f (adj2 1 l)
drop_last :: [t] -> [t]
drop_last l =
case l of
[] -> []
[_] -> []
e:l' -> e : drop_last l'
dropRight :: Int -> [a] -> [a]
dropRight n = reverse . drop n . reverse
dropWhileRight :: (a -> Bool) -> [a] -> [a]
dropWhileRight p = reverse . dropWhile p . reverse
take_right :: Int -> [a] -> [a]
take_right n = reverse . take n . reverse
take_while_right :: (a -> Bool) -> [a] -> [a]
take_while_right p = reverse . takeWhile p . reverse
at_head :: (a -> b) -> (a -> b) -> [a] -> [b]
at_head f g x =
case x of
[] -> []
e:x' -> f e : map g x'
at_last :: (a -> b) -> (a -> b) -> [a] -> [b]
at_last f g x =
case x of
[] -> []
[i] -> [g i]
i:x' -> f i : at_last f g x'
separate_last' :: [a] -> ([a],Maybe a)
separate_last' x =
case reverse x of
[] -> ([],Nothing)
e:x' -> (reverse x',Just e)
separate_last :: [a] -> ([a],a)
separate_last = fmap (fromMaybe (error "separate_last")) . separate_last'
indicate_repetitions :: Eq a => [a] -> [Maybe a]
indicate_repetitions =
let f l = case l of
[] -> []
e:l' -> Just e : map (const Nothing) l'
in concatMap f . group
zip_with_adj :: (a -> a -> b) -> [a] -> [b]
zip_with_adj f xs = zipWith f xs (tail xs)
compare_adjacent_by :: (a -> a -> Ordering) -> [a] -> [Ordering]
compare_adjacent_by = zip_with_adj
compare_adjacent :: Ord a => [a] -> [Ordering]
compare_adjacent = compare_adjacent_by compare
adjacent_groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
adjacent_groupBy f p =
case p of
[] -> []
[x] -> [[x]]
x:y:p' -> let r = adjacent_groupBy f (y:p')
r0:r' = r
in if f x y
then (x:r0) : r'
else [x] : r
group_ranges :: (Num t, Eq t) => [t] -> [(t,t)]
group_ranges =
let f l = (head l,last l)
in map f . adjacent_groupBy (\p q -> p + 1 == q)
group_just :: [Maybe a] -> [[Maybe a]]
group_just = group_on isJust
all_equal :: Eq a => [a] -> Bool
all_equal l =
case l of
[] -> True
[_] -> True
x:xs -> all id (map (== x) xs)
all_eq :: Eq n => [n] -> Bool
all_eq = (== 1) . length . nub
sort_group_on :: Ord b => (a -> b) -> [a] -> [[a]]
sort_group_on f = group_on f . sortOn f
mcons :: Maybe a -> [a] -> [a]
mcons e l = maybe l (:l) e
type Compare_F a = a -> a -> Ordering
two_stage_compare :: Compare_F a -> Compare_F a -> Compare_F a
two_stage_compare f g p q =
case f p q of
EQ -> g p q
r -> r
n_stage_compare :: [Compare_F a] -> Compare_F a
n_stage_compare l p q =
case l of
[] -> EQ
f:l' -> case f p q of
EQ -> n_stage_compare l' p q
r -> r
sort_to :: Ord i => [e] -> [i] -> [e]
sort_to e = map fst . sortOn snd . zip e
sort_on :: Ord i => [i] -> [e] -> [e]
sort_on = flip sort_to
sort_by_two_stage :: (Ord b,Ord c) => (a -> b) -> (a -> c) -> [a] -> [a]
sort_by_two_stage f g = sortBy (two_stage_compare (compare `on` f) (compare `on` g))
sort_by_n_stage :: Ord b => [a -> b] -> [a] -> [a]
sort_by_n_stage f = sortBy (n_stage_compare (map (compare `on`) f))
merge_by :: Compare_F a -> [a] -> [a] -> [a]
merge_by = O.mergeBy
merge_on :: Ord x => (a -> x) -> [a] -> [a] -> [a]
merge_on f = merge_by (compare `on` f)
merge_by_two_stage :: Ord b => (a -> b) -> Compare_F c -> (a -> c) -> [a] -> [a] -> [a]
merge_by_two_stage f cmp g = O.mergeBy (two_stage_compare (compare `on` f) (cmp `on` g))
merge :: Ord a => [a] -> [a] -> [a]
merge = O.merge
merge_set_by :: (a -> a -> Ordering) -> [[a]] -> [a]
merge_set_by f = foldr (merge_by f) []
merge_set :: Ord a => [[a]] -> [a]
merge_set = merge_set_by compare
merge_by_resolve :: (a -> a -> a) -> Compare_F a -> [a] -> [a] -> [a]
merge_by_resolve jn cmp =
let recur p q =
case (p,q) of
([],_) -> q
(_,[]) -> p
(l:p',r:q') -> case cmp l r of
LT -> l : recur p' q
EQ -> jn l r : recur p' q'
GT -> r : recur p q'
in recur
find_non_ascending :: (a -> a -> Ordering) -> [a] -> Maybe (a,a)
find_non_ascending cmp xs =
case xs of
p:q:xs' -> if cmp p q == GT then Just (p,q) else find_non_ascending cmp (q:xs')
_ -> Nothing
is_ascending_by :: (a -> a -> Ordering) -> [a] -> Bool
is_ascending_by cmp = isNothing . find_non_ascending cmp
is_ascending :: Ord a => [a] -> Bool
is_ascending = is_ascending_by compare
elem_ordered :: Ord t => t -> [t] -> Bool
elem_ordered = O.member
elemIndex_ordered :: Ord t => t -> [t] -> Maybe Int
elemIndex_ordered e =
let recur k l =
case l of
[] -> Nothing
x:l' -> if e == x
then Just k
else if x > e
then Nothing
else recur (k + 1) l'
in recur 0
zip_with_kr :: (a -> b -> c) -> [a] -> [b] -> ([c],[b])
zip_with_kr f =
let go r p q =
case (p,q) of
(i:p',j:q') -> go (f i j : r) p' q'
_ -> (reverse r,q)
in go []
zip_with_perhaps_rhs :: (a -> b -> Either c c) -> (a -> c) -> [a] -> [b] -> [c]
zip_with_perhaps_rhs f g lhs rhs =
case (lhs,rhs) of
([],_) -> []
(_,[]) -> map g lhs
(p:lhs',q:rhs') -> case f p q of
Left r -> r : zip_with_perhaps_rhs f g lhs' rhs
Right r -> r : zip_with_perhaps_rhs f g lhs' rhs'
fill_gaps_ascending :: (Enum n, Ord n) => t -> (n,n) -> [(n,t)] -> [(n,t)]
fill_gaps_ascending def_e (l,r) =
let f i (j,e) = if j > i then Left (i,def_e) else Right (j,e)
g i = (i,def_e)
in zip_with_perhaps_rhs f g [l .. r]
fill_gaps_ascending' :: (Num n,Enum n, Ord n) => t -> (n,n) -> [(n,t)] -> [(n,t)]
fill_gaps_ascending' def (l,r) =
let recur n x =
if n > r
then []
else case x of
[] -> zip [n .. r] (repeat def)
(m,e):x' -> if n < m
then (n,def) : recur (n + 1) x
else (m,e) : recur (n + 1) x'
in recur l
minmax :: Ord t => [t] -> (t,t)
minmax inp =
case inp of
[] -> error "minmax: null"
x:xs -> let mm p (l,r) = (min p l,max p r) in foldr mm (x,x) xs
bimap1 :: (t -> u) -> (t,t) -> (u,u)
bimap1 f (p,q) = (f p,f q)
pad_right :: a -> Int -> [a] -> [a]
pad_right k n l = take n (l ++ repeat k)
pad_left :: a -> Int -> [a] -> [a]
pad_left k n l = replicate (n length l) k ++ l
embedding :: Eq t => ([t],[t]) -> Either [Int] [Int]
embedding =
let recur n r (p,q) =
case (p,q) of
(_,[]) -> Right (reverse r)
([],_) -> Left (reverse r)
(x:p',y:q') ->
let n' = n + 1
r' = if x == y then n : r else r
in recur n' r' (p',if x == y then q' else q)
in recur 0 []
embedding_err :: Eq t => ([t],[t]) -> [Int]
embedding_err = either (error "embedding_err") id . embedding
is_embedding :: Eq t => [t] -> [t] -> Bool
is_embedding p q = isRight (embedding (p,q))
all_embeddings_m :: (Eq t,L.MonadLogic m) => [t] -> [t] -> m [Int]
all_embeddings_m p q =
let q_n = length q
recur p' q' n k =
if n == q_n
then return (reverse k)
else do (m,c) <- L.msum (map return p')
let k0:_ = k
c':_ = q'
L.guard (c == c' && (null k || m > k0))
let _:p'' = p'
_:q'' = q'
recur p'' q'' (n + 1) (m : k)
in recur (zip [0..] p) q 0 []
all_embeddings :: Eq t => [t] -> [t] -> [[Int]]
all_embeddings p = L.observeAll . all_embeddings_m p
unlist1 :: [t] -> Maybe t
unlist1 l =
case l of
[e] -> Just e
_ -> Nothing
unlist1_err :: [t] -> t
unlist1_err = fromMaybe (error "unlist1") . unlist1
adopt_shape :: T.Traversable t => (a -> b -> c) -> [b] -> t a -> t c
adopt_shape jn l =
let f (i:j) k = (j,jn k i)
f [] _ = error "adopt_shape: rhs ends"
in snd . T.mapAccumL f l
adopt_shape_m :: T.Traversable t => (a -> b-> c) -> [b] -> t (Maybe a) -> t (Maybe c)
adopt_shape_m jn l =
let f (i:j) k = case k of
Nothing -> (i:j,Nothing)
Just k' -> (j,Just (jn k' i))
f [] _ = error "adopt_shape_m: rhs ends"
in snd . T.mapAccumL f l
group_tree :: (a -> Bool,a -> Bool) -> [a] -> Tree (Maybe a)
group_tree (open_f,close_f) =
let unit e = Node (Just e) []
nil = Node Nothing []
insert_e (Node t l) e = Node t (e:l)
reverse_n (Node t l) = Node t (reverse l)
do_push (r,z) e =
case z of
h:z' -> (r,insert_e h (unit e) : z')
[] -> (unit e : r,[])
do_open (r,z) = (r,nil:z)
do_close (r,z) =
case z of
h0:h1:z' -> (r,insert_e h1 (reverse_n h0) : z')
h:z' -> (reverse_n h : r,z')
[] -> (r,z)
go st x =
case x of
[] -> Node Nothing (reverse (fst st))
e:x' -> if open_f e
then go (do_push (do_open st) e) x'
else if close_f e
then go (do_close (do_push st e)) x'
else go (do_push st e) x'
in go ([],[])
remove_ix :: Int -> [a] -> [a]
remove_ix k l = let (p,q) = splitAt k l in p ++ tail q
operate_ixs :: Bool -> [Int] -> [a] -> [a]
operate_ixs mode k =
let sel = if mode then notElem else elem
f (n,e) = if n `sel` k then Nothing else Just e
in mapMaybe f . zip [0..]
select_ixs :: [Int] -> [a] -> [a]
select_ixs = operate_ixs True
remove_ixs :: [Int] -> [a] -> [a]
remove_ixs = operate_ixs False
replace_ix :: (a -> a) -> Int -> [a] -> [a]
replace_ix f i p =
let (q,r:s) = splitAt i p
in q ++ (f r : s)
at_cyclic :: [a] -> Int -> a
at_cyclic l n =
let m = Map.fromList (zip [0..] l)
k = Map.size m
n' = n `mod` k
in fromMaybe (error "cyc_at") (Map.lookup n' m)