module Camfort.Helpers where
import GHC.Generics
import Data.Generics.Zipper
import Data.Generics.Aliases
import Data.Generics.Uniplate.Operations
import qualified Data.Generics.Str as Str
import Data.Data
import Data.Maybe
import Data.Monoid
import Data.List (elemIndices, group, sort, nub)
import qualified Data.ByteString.Char8 as B
import System.Directory
import Data.List (union)
import qualified Data.Map.Lazy as Map hiding (map, (\\))
import Control.Monad.Writer.Strict
collect :: (Eq a, Ord k) => [(k, a)] -> Map.Map k [a]
collect = Map.fromListWith union . map (fmap (:[]))
type Filename = String
type Directory = String
type SourceText = B.ByteString
type FileOrDir = String
getDir :: String -> String
getDir file = let ixs = elemIndices '/' file
in if null ixs then file
else take (last $ ixs) file
checkDir f = case (elemIndices '/' f) of
[] -> return ()
ix -> let d = take (last ix) f
in createDirectoryIfMissing True d
isDirectory :: FileOrDir -> IO Bool
isDirectory s = doesDirectoryExist s
fanout :: (a -> b) -> (a -> c) -> a -> (b, c)
fanout f g x = (f x, g x)
(<>) :: (a -> b) -> (a -> c) -> a -> (b, c)
f <> g = fanout f g
(><) :: (a -> c) -> (b -> d) -> (a, b) -> (c, d)
f >< g = \(x, y) -> (f x, g y)
lookups :: Eq a => a -> [(a, b)] -> [b]
lookups _ [] = []
lookups x ((a, b):xs) = if (x == a) then b : lookups x xs
else lookups x xs
lookups' :: Eq a => a -> [((a, b), c)] -> [(b, c)]
lookups' _ [] = []
lookups' x (((a, b), c):xs) = if (x == a) then (b, c) : lookups' x xs
else lookups' x xs
pairs :: [a] -> [(a, a)]
pairs [] = []
pairs (x:xs) = (zip (repeat x) xs) ++ (pairs xs)
mfmap :: Functor f => (a -> b) -> [f a] -> [f b]
mfmap f = map (fmap f)
each = flip (map)
cmpEq :: Ordering -> Bool
cmpEq EQ = True
cmpEq _ = False
cmpFst :: (a -> a -> Ordering) -> (a, b) -> (a, b) -> Ordering
cmpFst c (x1, y1) (x2, y2) = c x1 x2
cmpSnd :: (b -> b -> Ordering) -> (a, b) -> (a, b) -> Ordering
cmpSnd c (x1, y1) (x2, y2) = c y1 y2
type (:?) a (b :: k) = a
foldPair :: (a -> a -> Maybe a) -> [a] -> [a]
foldPair f [] = []
foldPair f [a] = [a]
foldPair f (a:(b:xs)) = case f a b of
Nothing -> a : (foldPair f (b : xs))
Just c -> foldPair f (c : xs)
class PartialMonoid x where
emptyM :: x
appendM :: x -> x -> Maybe x
normalise :: (Ord t, PartialMonoid t) => [t] -> [t]
normalise = nub . reduce . sort
where reduce = foldPair appendM
normaliseNoSort :: (Ord t, PartialMonoid t) => [t] -> [t]
normaliseNoSort = nub . reduce
where reduce = foldPair appendM
normaliseBy :: Ord t => (t -> t -> Maybe t) -> [t] -> [t]
normaliseBy plus = nub . (foldPair plus) . sort
#if __GLASGOW_HASKELL__ < 800
instance Monoid x => Monad ((,) x) where
return a = (mempty, a)
(x, a) >>= k = let (x', b) = k a
in (mappend x x', b)
#endif
reduceCollect :: (Data s, Data t, Uniplate t, Biplate t s) => (s -> Maybe a) -> t -> [a]
reduceCollect k x = execWriter (transformBiM (\y -> do case k y of
Just x -> tell [x]
Nothing -> return ()
return y) x)
everywhere :: (Zipper a -> Zipper a) -> Zipper a -> Zipper a
everywhere k z = everywhere' z
where
everywhere' = enterRight . enterDown . k
enterDown z =
case (down' z) of
Just dz -> let dz' = everywhere' dz
in case (up $ dz') of
Just uz -> uz
Nothing -> dz'
Nothing -> z
enterRight z =
case (right z) of
Just rz -> let rz' = everywhere' rz
in case (left $ rz') of
Just lz -> lz
Nothing -> rz'
Nothing -> z
zfmap :: Data a => (a -> a) -> Zipper (d a) -> Zipper (d a)
zfmap f x = zeverywhere (mkT f) x
data Reverse f a = Reverse { unwrapReverse :: f a }
instance Functor (Reverse Str.Str) where
fmap f (Reverse s) = Reverse (fmap f s)
instance Foldable (Reverse Str.Str) where
foldMap f (Reverse x) = foldMap f x
instance Traversable (Reverse Str.Str) where
traverse f (Reverse Str.Zero) = pure $ Reverse Str.Zero
traverse f (Reverse (Str.One x)) = (Reverse . Str.One) <$> f x
traverse f (Reverse (Str.Two x y)) = (\y x -> Reverse $ Str.Two x y)
<$> (fmap unwrapReverse . traverse f . Reverse $ y)
<*> (fmap unwrapReverse . traverse f . Reverse $ x)
descendReverseM :: (Data on, Monad m, Uniplate on) => (on -> m on) -> on -> m on
descendReverseM f x =
liftM generate . fmap unwrapReverse . traverse f . Reverse $ current
where (current, generate) = uniplate x
descendBiReverseM :: (Data from, Data to, Monad m, Biplate from to) => (to -> m to) -> from -> m from
descendBiReverseM f x =
liftM generate . fmap unwrapReverse . traverse f . Reverse $ current
where (current, generate) = biplate x