packages feed

bizzlelude-4.20.2.0.4: src/main/Misc.hs

{-# LANGUAGE NoImplicitPrelude #-}
{-# OPTIONS_GHC -fno-warn-missing-import-lists #-}
module Misc((|>), (&>), (&>=), (>>>), (>=>), (/#), (|*>), (<*|), aempty, andIfValidMV, andIfValidV, asString, asPath, asText, showText, concat, error, fromEither, headMaybe, lastMaybe, map, pam, (<&>), cartProduct, regexMatch, groupOn, length, mapMSequA, orElse, return', scalaGroupBy, putStrFlush, traceLabel, unsafeRead, listDirsRecursively, uncurry5, uncurry6) where

import External

import GHC.Real(Fractional((/)))

import Text.Regex.PCRE((=~))

import qualified Control.Applicative   as Apply
import qualified Control.Arrow         as CArrow
import qualified Control.Monad         as CMonad
import qualified Data.Either           as Either
import qualified Data.Foldable         as Foldable
import qualified Data.List             as List
import qualified Data.List.NonEmpty    as NE
import qualified Data.Text             as Text
import qualified Data.Text.IO          as TIO
import qualified Data.Text.Read        as DTR
import qualified GHC.Err               as Err
import qualified System.Directory      as SD
import qualified System.IO             as SIO

(/#) :: (Real a, Real b) => a -> b -> Double
a /# b = (realToFrac a) / (realToFrac b)

(|>) :: a -> (a -> b) -> b
a |> f = f a

(&>), (>>>) :: (a -> b) -> (b -> c) -> (a -> c)
(>>>) = (CArrow.>>>)
(&>)  = (>>>)

(&>=), (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
(>=>) = (CMonad.>=>)
(&>=) = (>=>)

infixl 2 >>>, >=>
infixl 1 |>

(<*|) :: (Monad m, Applicative a) => m (a x) -> m (a x) -> m (a x)
(<*|) a b =
  do
    va <- a
    vb <- b
    return $ va <* vb

(|*>) :: (Monad m, Applicative a) => m (a x) -> m (a x) -> m (a x)
(|*>) a b =
  do
    va <- a
    vb <- b
    return $ va *> vb

aempty :: Apply.Alternative f => f a
aempty = Apply.empty

asString :: Text -> String
asString = Text.unpack

asPath :: Text -> FilePath
asPath = asString

asText :: String -> Text
asText = Text.pack

showText :: Show a => a -> Text
showText = show &> asText

concat :: (Foldable t, MonadPlus m) => t (m a) -> m a
concat = Foldable.msum

error :: Text -> a
error = asString &> Err.error

map :: (Functor f) => (a -> b) -> f a -> f b
map = fmap

pam, (<&>) :: Functor f => f a -> (a -> b) -> f b
pam   = flip map
(<&>) = flip map

mapMSequA :: (Monad m, Applicative f, Traversable t) => (a -> m (f b)) -> t a -> m (f (t b))
mapMSequA f xs =
  do
    resVs <- mapM f xs
    return $ sequenceA resVs

andIfValidV :: Monad m => Validation f s1 -> (s1 -> m (Validation f s2)) -> m (Validation f s2)
v `andIfValidV` vm = validation (Failure &> return) vm v

andIfValidMV :: Monad m => m (Validation f s1) -> (s1 -> m (Validation f s2)) -> m (Validation f s2)
sVM `andIfValidMV` f =
  do
    sV <- sVM
    sV `andIfValidV` f

orElse :: Maybe a -> a -> a
orElse m x = maybe x id m

headMaybe :: Foldable t => t a -> Maybe a
headMaybe = Foldable.toList &> helper
  where
    helper    [] = Nothing
    helper (h:_) = Just h

lastMaybe :: Foldable t => t a -> Maybe a
lastMaybe = Foldable.toList &> helper
  where
    helper [] = Nothing
    helper xs = Just $ List.last xs

length :: Foldable t => t a -> Word
length = Foldable.length &> fromIntegral

cartProduct :: [a] -> [b] -> [(a, b)]
cartProduct xs ys = [(x, y) | x <- xs, y <- ys]

regexMatch :: Text -> Text -> Maybe [Text]
regexMatch regex text =
  case (Text.unpack text) =~ ("(?sm)" <> Text.unpack regex) :: [[String]] of
    []       -> Nothing
    captures -> Just [Text.pack group | (_full : groups) <- captures, group <- groups]

unsafeNonEmpty :: [a] -> NonEmpty a
unsafeNonEmpty = NE.nonEmpty &> maybe (error "`unsafeNonEmpty` is unsafe") id

fromEither :: Either a a -> a
fromEither = either id id

groupOn :: Ord criterion => (item -> criterion) -> [item] -> [NonEmpty item]
groupOn f = sort &> group &> (map $ unsafeNonEmpty)
  where
    sort  = List.sortBy (compare `on` f)
    group = List.groupBy ((==) `on` f)

return' :: (Monad m) => a -> m a
return' = (return $!)

scalaGroupBy :: Ord criterion => (item -> criterion) -> [item] -> [(criterion, NonEmpty item)]
scalaGroupBy f = (groupOn f) &> pair
  where
    pair  = tee $ NE.head &> f
    tee f = map $ f &&& id

-- Hack to make GHCI print this before the prompt --Jason B. (2/20/17)
putStrFlush :: Text -> IO ()
putStrFlush x = (TIO.putStr x) >>= (const $ SIO.hFlush SIO.stdout)

traceLabel :: (Show a) => Text -> a -> a
traceLabel label a = traceShow (label <> ": " <> (showText a)) a

unsafeRead :: Integral a => Text -> a
unsafeRead = DTR.decimal &> (Either.either (error "Well, that read *was* unsafe...") id) &> fst

listDirsRecursively :: FilePath -> IO [FilePath]
listDirsRecursively filepath =
  do
    paths    <- SD.listDirectory filepath
    dirs     <- paths |> ((map $ \x -> filepath <> "/" <> x) &> (filterM SD.doesDirectoryExist))
    children <- mapM listDirsRecursively dirs
    return $ dirs <> (concat children)

uncurry5 :: (a -> b -> c -> d -> e -> f) -> ((a, b, c, d, e) -> f)
uncurry5 f (a, b, c, d, e) = f a b c d e

uncurry6 :: (a -> b -> c -> d -> e -> f -> g) -> ((a, b, c, d, e, f) -> g)
uncurry6 g (a, b, c, d, e, f) = g a b c d e f