packages feed

rfc-prelude-0.0.0.1: src/RFC/Prelude.hs

{-# LANGUAGE CPP              #-}
{-# LANGUAGE FlexibleContexts #-}

module RFC.Prelude
  ( module RFC.Prelude
  , module RFC.Data.UUID
  , module GHC.Generics
  , module Text.Read
  , module Data.Time.Units
  , module Data.Function
  , module Data.Typeable
  , module Control.Monad
  , module Data.Bitraversable
  , module Data.Bifunctor
  , module Data.Bifoldable
  , module Data.Default
  , module ClassyPrelude
  , module Control.Monad.Trans.Control
  , module Data.Word
  , module Data.Semigroup
  , module Control.Monad.Fail
  , module Data.Time.Clock
  , module UnliftIO
  , module GHC.Exts
  , module Data.Proxy
  , module Data.Ratio
  , module Data.Tuple.Curry
  , module Data.Either
  , module Data.Int
  , module RFC.Prelude.Instances
  , module RFC.Prelude.JSON
  , module RFC.Prelude.String
  , module RFC.Prelude.Concurrent
  ) where

import           ClassyPrelude                hiding
  ( Day, fail, fromList, map, readMay, toList, unpack, (++) )
import           Control.Monad                ( forever, void, (<=<), (>=>) )
import           Control.Monad.Fail           ( MonadFail, fail )
import           Control.Monad.Trans.Control
import           Data.Bifoldable
import           Data.Bifunctor
import           Data.Bitraversable
import           Data.Char                    as Char
import           Data.Default
import           Data.Either                  ( Either (..) )
import qualified Data.Foldable                as Foldable
import           Data.Function                ( (&) )
import           Data.Int
import qualified Data.List                    as List
import           Data.Proxy                   ( Proxy (..) )
import           Data.Ratio                   ( Ratio, Rational )
import           Data.Semigroup
import           Data.Time.Clock
import           Data.Time.Units
import           Data.Tuple.Curry             ( curryN, uncurryN )
import           Data.Typeable                ( TypeRep, typeOf )
import           Data.Word                    ( Word16 )
import           GHC.Exts                     ( IsList (..), fromListN )
import           GHC.Generics                 ( Generic )
import           Math.NumberTheory.Logarithms ( integerLog2 )
import           RFC.Data.UUID                ( UUID )
import           RFC.Prelude.Concurrent
import           RFC.Prelude.Instances
import           RFC.Prelude.JSON
import           RFC.Prelude.String
import           Text.Read                    ( Read, read, readMaybe )
import           UnliftIO

#ifdef VERSION_exceptions
import           Control.Monad.Catch
#endif

{-# ANN module "HLint: ignore Use if" #-}

readMay :: (ToText input, Read output) => input -> Maybe output
readMay = readMaybe . fromText . toText
{-# INLINEABLE readMay #-}
{-# SPECIALIZE INLINE readMay :: (Read output) => StrictText -> Maybe output #-}
{-# SPECIALIZE INLINE readMay :: (Read output) => String -> Maybe output #-}

-- | Unwraps an 'Either', returning a default value if it is a 'Left'.
fromRight :: b -> Either a b -> b
fromRight _ (Right b) = b
fromRight b (Left  _) = b
{-# INLINE fromRight #-}

-- | Unwraps an 'Either', returning a default value if it is a 'Right'.
fromLeft :: a -> Either a b -> a
fromLeft a (Right _) = a
fromLeft _ (Left  a) = a
{-# INLINE fromLeft #-}

-- | An equivalent to 'maybe' for 'Right'.
right :: x -> (b -> x) -> Either a b -> x
right _ f (Right b) = f b
right x _ (Left _)  = x
{-# INLINE right #-}
{-# SPECIALIZE INLINE right :: x -> (String -> x) -> Either a String -> x #-}

-- | An equivalent to 'maybe' for 'Left'.
left :: x -> (a -> x) -> Either a b -> x
left _ f (Left a)  = f a
left x _ (Right _) = x
{-# INLINE left #-}
{-# SPECIALIZE INLINE left :: x -> (String -> x) -> Either String b -> x #-}

-- | Our implementation of if, which is pretty much exactly what you would suspect.
ifThenElse :: Bool -> a -> a -> a
ifThenElse test true false =
  case test of
    True  -> true
    False -> false
{-# INLINE ifThenElse #-}

charIsUpper :: Char -> Bool
charIsUpper = Char.isUpper
{-# INLINE charIsUpper #-}

charIsLower :: Char -> Bool
charIsLower = Char.isLower
{-# INLINE charIsLower #-}

uniq :: (Eq a) => [a] -> [a]
uniq = List.nub
{-# INLINE uniq #-}

safeHead :: (MonadFail m, Foldable f) => f a -> m a
safeHead xs =
  case Foldable.toList xs of
    []    -> fail "Attempted to head an empty list"
    (x:_) -> return x
{-# INLINE safeHead #-}
{-# SPECIALIZE INLINE safeHead :: [a] -> Maybe a #-}
{-# SPECIALIZE INLINE safeHead :: [a] -> IO a #-}

lg :: Integer -> Integer
lg z
  | z > 0 = toInteger $ integerLog2 z
  | z == 0 = 0
  | otherwise = toInteger $ integerLog2 (-1 * z)
{-# INLINE lg #-}

lg' :: (Integral z, Integral z') => z -> z'
lg' = fromInteger . lg . toInteger
{-# INLINEABLE lg' #-}
{-# SPECIALIZE INLINE lg' :: Integer -> Integer             #-}
{-# SPECIALIZE INLINE lg' :: (Integral z') => Integer -> z' #-}
{-# SPECIALIZE INLINE lg' :: (Integral z ) => z -> Int      #-}
{-# SPECIALIZE INLINE lg' :: (Integral z ) => z -> Integer  #-}
{-# SPECIALIZE INLINE lg' :: Word -> Word                   #-}

isSingleton :: (Foldable f) => f a -> Bool
isSingleton xs =
  case Foldable.toList xs of
    [_] -> True
    _   -> False
{-# INLINEABLE isSingleton #-}
{-# SPECIALIZE INLINE isSingleton :: [a] -> Bool   #-}
{-# SPECIALIZE INLINE isSingleton :: Seq a -> Bool #-}

fmap2 :: (Functor f, Functor g) => (a -> b) -> f(g a) -> f(g b)
fmap2 f x = fmap f <$> x
{-# INLINE fmap2 #-}
{-# SPECIALIZE INLINE fmap2 :: Functor g => (a->b) -> [g a] -> [g b]  #-}
{-# SPECIALIZE INLINE fmap2 :: Functor f => (a->b) -> f [a] -> f [b]  #-}
{-# SPECIALIZE INLINE fmap2 :: Functor g => (a->b) -> IO (g a) -> IO (g b) #-}
{-# SPECIALIZE INLINE fmap2 :: Functor f => (a->b) -> f (IO a) -> f (IO b) #-}
{-# SPECIALIZE INLINE fmap2 :: Functor g => (a->b) -> Maybe (g a) -> Maybe (g b) #-}
{-# SPECIALIZE INLINE fmap2 :: Functor f => (a->b) -> f (Maybe a) -> f (Maybe b) #-}

infixl 4 <$$>
(<$$>) :: (Functor f, Functor g) => (a -> b) -> f(g a) -> f(g b)
(<$$>) = fmap2
{-# INLINE (<$$>) #-}
{-# SPECIALIZE INLINE (<$$>) :: Functor g => (a->b) -> [g a] -> [g b]  #-}
{-# SPECIALIZE INLINE (<$$>) :: Functor f => (a->b) -> f [a] -> f [b]  #-}
{-# SPECIALIZE INLINE (<$$>) :: Functor g => (a->b) -> IO (g a) -> IO (g b) #-}
{-# SPECIALIZE INLINE (<$$>) :: Functor f => (a->b) -> f (IO a) -> f (IO b) #-}
{-# SPECIALIZE INLINE (<$$>) :: Functor g => (a->b) -> Maybe (g a) -> Maybe (g b) #-}
{-# SPECIALIZE INLINE (<$$>) :: Functor f => (a->b) -> f (Maybe a) -> f (Maybe b) #-}