alms-0.6.0: src/Util.hs
-- | Utility functions
module Util (
-- * Extra collection operations
-- ** Shallow mapping of 'Traversable's
mapHead, mapTail, mapInit, mapLast,
-- ** 'Foldable'/'Applicative' operations
allA, anyA,
-- ** 2-way 'Foldable' operations
foldl2, foldr2, all2, any2,
allA2, anyA2,
-- ** Extra zips
zip4, unzip4, zip5, unzip5,
-- ** List operations
mapCons, foldM1,
lookupWithIndex, listNth, ordNub, partitionJust,
-- *** Unfold with an accumulator
unscanr, unscanl,
-- *** Map in CPS
mapCont, mapCont_,
-- * Extra monadic operations
whenM, unlessM, concatMapM, before,
-- * Maps for state-like monads
mapListen2, mapListen3,
-- * 'Maybe' and 'Either' operations
fromOptA, unEither,
-- * More convenience
-- ** Maybe functions
(?:),
-- ** Either funtions
isLeft, isRight,
-- ** List functions
splitBy,
-- ** Monomorphic @ord@ and @chr@
char2integer, integer2char,
-- ** For defining 'Ord'
thenCmp, thenCmpM,
-- ** Versions of fmap and compose
(>>!),
(<$$>), (<$$$>), (<$$$$>), (<$$$$$>), (<$$$$$$>),
(<$.>), (<$$.>), (<$$$.>), (<$$$$.>),
(<->), (<-->), (<--->), (<---->), (<----->),
-- * Generic set operations
SetLike(..), SetLike2(..),
-- * Re-exports
module Control.Arrow,
module Control.Applicative,
module Control.Monad,
module Control.Monad.Error,
module Control.Monad.Identity,
module Control.Monad.List,
module Control.Monad.RWS.Strict,
module Control.Monad.Reader,
module Control.Monad.State.Strict,
module Control.Monad.Trans,
module Control.Monad.Writer.Strict,
module Data.Foldable,
module Data.Function,
module Data.Maybe,
module Data.Monoid,
module Data.Traversable,
module Data.Tuple.All,
module Data.OptionalClass,
module Data.Perhaps,
module Util.Bogus,
module Util.Viewable,
module Prelude,
) where
import Prelude hiding ( (=<<), Functor(..), Maybe(..), Monad(..), all,
and, any, concat, concatMap, elem, foldl, foldl1,
foldr, foldr1, mapM, mapM_, maximum, maybe,
minimum, notElem, or, product, sequence, sequence_,
sum )
import Control.Arrow ( Arrow(..), ArrowChoice(..), (>>>), (<<<) )
import Control.Applicative hiding ( empty )
import Control.Monad hiding ( forM, forM_, mapM_, mapM, msum,
sequence, sequence_ )
import Control.Monad.Error ( MonadError(..), ErrorT(..), mapErrorT,
Error(..) )
import Control.Monad.Identity ( Identity(..) )
import Control.Monad.List ( ListT(..), mapListT )
import Control.Monad.RWS.Strict ( RWST(..), runRWST, execRWST, evalRWST,
mapRWST, evalRWS )
import Control.Monad.Reader ( MonadReader(..), ReaderT(..), mapReaderT,
asks, runReader )
import Control.Monad.State.Strict ( MonadState(..), StateT(..), evalStateT,
execStateT, evalState, gets, modify,
mapStateT )
import Control.Monad.Trans ( MonadTrans(..), MonadIO(..) )
import Control.Monad.Writer.Strict ( MonadWriter(..), WriterT(..),
runWriter, execWriterT, execWriter,
mapWriterT, censor, listens )
import Data.Char (chr, ord)
import Data.Maybe
import Data.Monoid
import Data.Foldable
import Data.Function ( on )
import Data.Traversable
import Data.Tuple.All
import Data.OptionalClass
import Data.Perhaps
import Util.Bogus
import Util.Viewable
import qualified Data.Set as S
import qualified Data.List as L
mapHead, mapTail, mapInit, mapLast ∷ Traversable t ⇒ (a → a) → t a → t a
mapHead f = snd . mapAccumL each True where
each True x = (False, f x)
each _ x = (False, x)
mapTail f = snd . mapAccumL each True where
each True x = (False, x)
each _ x = (False, f x)
mapInit f = snd . mapAccumR each True where
each True x = (False, x)
each _ x = (False, f x)
mapLast f = snd . mapAccumR each True where
each True x = (False, f x)
each _ x = (False, x)
-- | 'all' with an applicative predicate
allA ∷ (Applicative f, Foldable t) ⇒ (a → f Bool) → t a → f Bool
allA p xs = and <$> traverse p (toList xs)
-- | 'any' with an applicative predicate
anyA ∷ (Applicative f, Foldable t) ⇒ (a → f Bool) → t a → f Bool
anyA p xs = or <$> traverse p (toList xs)
-- | Left-associative fold over two lists
foldl2 ∷ (Foldable t1, Foldable t2) ⇒
(c → a → b → c) → c → t1 a → t2 b → c
foldl2 f z xs ys = foldl (uncurry . f) z (zip (toList xs) (toList ys))
-- | Right-associative fold over two lists
foldr2 ∷ (Foldable t1, Foldable t2) ⇒
(a → b → c → c) → c → t1 a → t2 b → c
foldr2 f z xs ys = foldr (uncurry f) z (zip (toList xs) (toList ys))
-- | Two-list 'all'
all2 :: (Foldable f1, Foldable f2) ⇒
(a -> b -> Bool) -> f1 a -> f2 b -> Bool
all2 p xs ys = and (zipWith p (toList xs) (toList ys))
-- | Two-list 'any'
any2 :: (Foldable f1, Foldable f2) ⇒
(a -> b -> Bool) -> f1 a -> f2 b -> Bool
any2 p xs ys = or (zipWith p (toList xs) (toList ys))
-- | 'all' for two 'Foldable's with an applicative predicate
allA2 ∷ (Applicative f, Foldable t1, Foldable t2) ⇒
(a → b → f Bool) → t1 a → t2 b → f Bool
allA2 p xs ys = allA id (zipWith p (toList xs) (toList ys))
-- | 'all' for two 'Foldable's with an applicative predicate
anyA2 ∷ (Applicative f, Foldable t1, Foldable t2) ⇒
(a → b → f Bool) → t1 a → t2 b → f Bool
anyA2 p xs ys = anyA id (zipWith p (toList xs) (toList ys))
-- | Zip four lists
zip4 ∷ [a] → [b] → [c] → [d] → [(a, b, c, d)]
zip4 (a:as) (b:bs) (c:cs) (d:ds) = (a, b, c, d) : zip4 as bs cs ds
zip4 _ _ _ _ = []
-- | Zip five lists
zip5 ∷ [a] → [b] → [c] → [d] → [e] → [(a, b, c, d, e)]
zip5 (a:as) (b:bs) (c:cs) (d:ds) (e:es) = (a, b, c, d, e) : zip5 as bs cs ds es
zip5 _ _ _ _ _ = []
-- | Unzip four lists
unzip4 ∷ [(a, b, c, d)] → ([a], [b], [c], [d])
unzip4 = foldr (\(a,b,c,d) ~(as,bs,cs,ds) → (a:as,b:bs,c:cs,d:ds))
([],[],[],[])
-- | Unzip four lists
unzip5 ∷ [(a, b, c, d, e)] → ([a], [b], [c], [d], [e])
unzip5 = foldr (\(a,b,c,d,e) ~(as,bs,cs,ds,es) → (a:as,b:bs,c:cs,d:ds,e:es))
([],[],[],[],[])
-- | Apply one function to the head of a list and another to the
-- tail
mapCons :: (a -> b) -> ([a] -> [b]) -> [a] -> [b]
mapCons _ _ [] = []
mapCons fh ft (x:xs) = fh x : ft xs
-- | Fold over a non-empty 'Foldable' in a monad
foldM1 ∷ (Foldable t, Monad m) ⇒ (a → a → m a) → t a → m a
foldM1 f xs0 = loop (toList xs0) where
loop [] = fail "foldM1: empty"
loop (x:xs) = foldM f x xs
-- | Like 'Data.List.lookup', but returns the index into the list as
-- well.
lookupWithIndex ∷ Eq a ⇒ a → [(a, b)] → Maybe (b, Int)
lookupWithIndex k = loop 0 where
loop _ [] = Nothing
loop !ix ((k',v):rest)
| k == k' = Just (v, ix)
| otherwise = loop (ix + 1) rest
-- | Safe version of '(Data.List.!!)'
listNth ∷ Int → [a] → Maybe a
listNth i = foldr (const . Just) Nothing . drop i
-- | Like nub, but O(n log n) instead of O(n^2)
ordNub ∷ Ord a ⇒ [a] → [a]
ordNub = loop S.empty where
loop seen (x:xs)
| x `S.member` seen = loop seen xs
| otherwise = x : loop (S.insert x seen) xs
loop _ [] = []
-- | Partition a list into the portions where the function returns
-- 'Just' and the portions where it returns 'Nothing'
partitionJust ∷ (a → Maybe b) → [a] → ([a], [b])
partitionJust f = foldr each ([], []) where
each x (xs, ys) = case f x of
Nothing → (x:xs, ys)
Just y → (xs, y:ys)
-- | Unfold a list, left-to-right, returning the final state
unscanr :: (b -> Maybe (a, b)) -> b -> ([a], b)
unscanr f b = case f b of
Just (a, b') -> (a : fst rest, snd rest) where rest = unscanr f b'
Nothing -> ([], b)
-- | Unfold a list, right-to-left, returning the final state
unscanl :: (b -> Maybe (a, b)) -> b -> ([a], b)
unscanl f = loop [] where
loop acc b = case f b of
Just (a, b') -> loop (a : acc) b'
Nothing -> (acc, b)
-- | CPS version of 'map'
mapCont :: (a -> (b -> r) -> r) -> [a] -> ([b] -> r) -> r
mapCont _ [] k = k []
mapCont f (x:xs) k = f x $ \x' ->
mapCont f xs $ \xs' ->
k (x' : xs')
-- | CPS version of 'map_'
mapCont_ :: (a -> r -> r) -> [a] -> r -> r
mapCont_ _ [] k = k
mapCont_ f (x:xs) k = f x $ mapCont_ f xs $ k
whenM ∷ Monad m ⇒ m Bool → m () → m ()
whenM test branch = test >>= flip when branch
unlessM ∷ Monad m ⇒ m Bool → m () → m ()
unlessM test branch = test >>= flip unless branch
-- | Map and concatenate in a monad.
concatMapM ∷ (Foldable t, Monad m, Monoid b) ⇒ (a → m b) → t a → m b
concatMapM f = foldr (liftM2 mappend . f) (return mempty)
before ∷ Monad m ⇒ m a → (a → m b) → m a
before m k = do
a ← m
k a
return a
infixl 8 `before`
mapListen2 ∷ Monad m ⇒ (a → m ((b, s), w)) → a → m ((b, w), s)
mapListen3 ∷ Monad m ⇒ (a → m ((b, s1, s2), w)) → a → m ((b, w), s1, s2)
mapListen2 mapper action = do
((b, s), w) ← mapper action
return ((b, w), s)
mapListen3 mapper action = do
((b, s1, s2), w) ← mapper action
return ((b, w), s1, s2)
fromOptA ∷ (Applicative f, Optional t) ⇒ f a → t a → f a
fromOptA def = foldOpt def pure
unEither ∷ Either a a → a
unEither = either id id
-- | The ASCII value of a character
char2integer :: Char -> Integer
char2integer = fromIntegral . ord
-- | The character of an ASCII value
integer2char :: Integer -> Char
integer2char = chr . fromIntegral
-- | Break a list where the given preducate answers true
splitBy :: (a -> Bool) -> [a] -> [[a]]
splitBy _ [] = []
splitBy p xs = let (ys, zs) = break p xs
in ys : splitBy p (drop 1 zs)
-- | Maybe cons, maybe not
(?:) :: Optional t ⇒ t a -> [a] -> [a]
(?:) = foldOpt id (:)
infixr 5 ?:
isLeft, isRight :: Either a b -> Bool
isLeft (Left _) = True
isLeft _ = False
isRight (Right _) = True
isRight _ = False
-- | To combine two 'Ordering's in lexigraphic order
thenCmp :: Ordering -> Ordering -> Ordering
thenCmp EQ k2 = k2
thenCmp k1 _ = k1
-- | To combine two actions producing 'Ordering's in lexigraphic order
thenCmpM ∷ Monad m ⇒ m Ordering → m Ordering → m Ordering
thenCmpM m1 m2 = do
ordering ← m1
case ordering of
EQ → m2
_ → return ordering
infixr 4 `thenCmp`, `thenCmpM`
-- | @flip fmap@
(>>!) :: Functor f => f a -> (a -> b) -> f b
(>>!) = flip fmap
infixl 1 >>!
(<$$>) ∷ (Functor f, Functor g) ⇒
(b → c) → g (f b) → g (f c)
(<$$>) = fmap . fmap
(<$$$>) ∷ (Functor f, Functor g, Functor h) ⇒
(b → c) → h (g (f b)) →
h (g (f c))
(<$$$>) = fmap . fmap . fmap
(<$$$$>) ∷ (Functor f, Functor g, Functor h, Functor i) ⇒
(b → c) → i (h (g (f b))) →
i (h (g (f c)))
(<$$$$>) = fmap . fmap . fmap . fmap
(<$$$$$>) ∷ (Functor f, Functor g, Functor h, Functor i, Functor j) ⇒
(b → c) → j (i (h (g (f b)))) →
j (i (h (g (f c))))
(<$$$$$>) = fmap . fmap . fmap . fmap . fmap
(<$$$$$$>) ∷ (Functor f, Functor g, Functor h,
Functor i, Functor j, Functor k) ⇒
(b → c) → k (j (i (h (g (f b))))) →
k (j (i (h (g (f c)))))
(<$$$$$$>) = fmap . fmap . fmap . fmap . fmap . fmap
infixl 4 <$$>, <$$$>, <$$$$>, <$$$$$>, <$$$$$$>
(<$.>) ∷ (Arrow (⇝), Functor f) ⇒
f (b ⇝ c) → (a ⇝ b) →
f (a ⇝ c)
f <$.> g = (g >>>) <$> f
(<$$.>) ∷ (Arrow (⇝), Functor f, Functor g) ⇒
g (f (b ⇝ c)) → (a ⇝ b) →
g (f (a ⇝ c))
f <$$.> g = (g >>>) <$$> f
(<$$$.>) ∷ (Arrow (⇝), Functor f, Functor g, Functor h) ⇒
h (g (f (b ⇝ c))) → (a ⇝ b) →
h (g (f (a ⇝ c)))
f <$$$.> g = (g >>>) <$$$> f
(<$$$$.>) ∷ (Arrow (⇝), Functor f, Functor g, Functor h, Functor i) ⇒
i (h (g (f (b ⇝ c)))) → (a ⇝ b) →
i (h (g (f (a ⇝ c))))
f <$$$$.> g = (g >>>) <$$$$> f
infixl 4 <$.>, <$$.>, <$$$.>, <$$$$.>
(<->) ∷ Functor f ⇒
f (a → b) → a → f b
f <-> x = ($ x) <$> f
(<-->) ∷ (Functor f, Functor g) ⇒
f (g (a → b)) → a → f (g b)
f <--> x = (<-> x) <$> f
(<--->) ∷ (Functor f, Functor g, Functor h) ⇒
f (g (h (a → b))) → a → f (g (h b))
f <---> x = (<--> x) <$> f
(<---->) ∷ (Functor f, Functor g, Functor h, Functor i) ⇒
f (g (h (i (a → b)))) → a → f (g (h (i b)))
f <----> x = (<---> x) <$> f
(<----->) ∷ (Functor f, Functor g, Functor h, Functor i, Functor j) ⇒
f (g (h (i (j (a → b))))) → a → f (g (h (i (j b))))
f <-----> x = (<----> x) <$> f
infixl 4 <->, <-->, <--->, <---->, <----->
class (Eq a, Foldable t) ⇒ SetLike t a where
isEmptySet ∷ t a → Bool
(∈), (∉) ∷ a → t a → Bool
emptySet ∷ t a
singleton ∷ a → t a
--
isEmptySet = null . toList
a ∈ set = a `elem` toList set
a ∉ set = not (a ∈ set)
class (SetLike t a, SetLike t' a) ⇒ SetLike2 t t' a where
(⊆), (⊇), (/⊆), (/⊇), (/∩)
∷ t a → t' a → Bool
(∪), (∩), (∖) ∷ t a → t' a → t a
--
set1 ⊆ set2 = all (∈ set2) set1
set1 ⊇ set2 = all (∈ set1) set2
set1 /⊆ set2 = not (set1 /⊆ set2)
set1 /⊇ set2 = not (set1 /⊇ set2)
set1 /∩ set2 = not (any (∈ set2) set1)
infix 4 ∈, ∉, ⊆, ⊇, /⊆, /⊇, /∩
infixl 6 ∪, ∖
infixl 7 ∩
instance Eq a ⇒ SetLike [] a where
emptySet = []
singleton a = [a]
instance Eq a ⇒ SetLike2 [] [] a where
(∪) = L.union
(∩) = L.intersect
(∖) = (L.\\)
instance Ord a ⇒ SetLike2 [] S.Set a where
(∪) = L.union <$.> toList
(∩) = L.intersect <$.> toList
(∖) = (L.\\) <$.> toList
instance Ord a ⇒ SetLike S.Set a where
isEmptySet = S.null
(∈) = S.member
emptySet = S.empty
singleton = S.singleton
instance Ord a ⇒ SetLike2 S.Set S.Set a where
(⊆) = S.isSubsetOf
set1 /∩ set2 = isEmptySet (set1 ∩ set2)
(∪) = S.union
(∩) = S.intersection
(∖) = (S.\\)
instance Ord a ⇒ SetLike2 S.Set [] a where
(⊆) = (⊆) <$.> S.fromList
set1 ⊇ list2 = all (∈ set1) list2
set1 /∩ list2 = all (∉ set1) list2
(∪) = foldr S.insert
(∩) = (∩) <$.> S.fromList
(∖) = foldr S.delete