praglude (empty) → 0.1.1.0
raw patch · 4 files changed
+771/−0 lines, 4 filesdep +aesondep +basedep +base64-bytestringsetup-changed
Dependencies added: aeson, base, base64-bytestring, bytestring, casing, containers, data-default, deepseq, directory, filepath, hashable, lens, mtl, random, semigroups, string-convert, template-haskell, text, time, unordered-containers, vector
Files
- LICENSE +30/−0
- Setup.hs +2/−0
- praglude.cabal +44/−0
- src/Praglude.hs +695/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Tobias Dammers (c) 2016++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Tobias Dammers nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ praglude.cabal view
@@ -0,0 +1,44 @@+name: praglude+version: 0.1.1.0+synopsis: A pragmatic Prelude+description: An opinionated alternative Prelude, focused on practicality.+homepage: https://github.com/tdammers/praglude+license: BSD3+license-file: LICENSE+author: Tobias Dammers+maintainer: tdammers@gmail.com+copyright: 2016 Tobias Dammers+category: Web+build-type: Simple+-- extra-source-files:+cabal-version: >=1.10++library+ hs-source-dirs: src+ exposed-modules: Praglude+ build-depends: base >= 4.7 && < 5+ , aeson+ , bytestring+ , base64-bytestring+ , casing+ , containers+ , data-default+ , deepseq+ , directory+ , filepath+ , hashable+ , lens+ , template-haskell+ , mtl+ , random+ , semigroups+ , string-convert+ , text+ , time+ , unordered-containers+ , vector+ default-language: Haskell2010++source-repository head+ type: git+ location: https://github.com/tdammers/praglude
+ src/Praglude.hs view
@@ -0,0 +1,695 @@+{-#LANGUAGE TypeSynonymInstances #-}+{-#LANGUAGE FlexibleInstances #-}+{-#LANGUAGE MultiParamTypeClasses #-}+{-#LANGUAGE DeriveGeneric #-}+{-#LANGUAGE DeriveFunctor #-}+{-#LANGUAGE DeriveTraversable #-}+{-#LANGUAGE AutoDeriveTypeable #-}+{-#LANGUAGE GeneralizedNewtypeDeriving #-}+{-#LANGUAGE FunctionalDependencies #-}+module Praglude+(+-- * The Original Prelude+ module Prelude++-- * Monoids+, module Data.Monoid+, concat+, append+, empty++-- * Maybe+, module Data.Maybe++-- * Applicative+, (<|>)++-- * Monads+, module Control.Monad++-- * Arrows+, module Control.Arrow++-- * Mutable Variables In IO+, module Data.IORef+, module Control.Concurrent.MVar+, module Control.Concurrent.Chan++-- * Default+, module Data.Default++-- * Lens+, module Control.Lens++-- * State monads+, module Control.Monad.State++-- * Painless String Types+, s+, ToString (..)+, FromString+, IsString (..)++, Text+, LText+, ByteString+, LByteString++-- * Generalized String Operations++, trim+, ltrim+, rtrim+, words+, lines++, module Data.Char++-- * String Case Conversions+, kebab, snake, pascal++-- * I/O+, stderr+, stdout+, stdin+, Handle++-- * Environment+, module System.Environment++-- * Generalized I/O+, StringIO (..)++-- * Printf+, module Text.Printf++-- * Filename And File System Manipulation+, module System.FilePath+, module System.Directory++-- * Type Forcers+--+-- Useful for disambiguation+, asString+, asText+, asLText+, asByteString+, asLByteString+, asHashMap++-- * Container Types With Unified Interfaces++, module Data.Foldable++, AList (..)+, HashMap+, LHashMap+, HashSet+, Map+, Set+, Vector++, Hashable (..)+, Lookup (..)+, ListLike (..)+, DictLike (..)+, SetLike (..)+, Filterable (..)+, cull+, startsWith+, endsWith+, intercalate++-- * JSON+, ToJSON (..)+, FromJSON (..)+, Value+, object+, prettyJsonOptions+, derivePrettyJSON+, deriveJSON++, encodeJSON+, decodeJSON+, encodeJSONStrict+, decodeJSONStrict+, (~>)++-- * Base-64+, encodeBase64+, decodeBase64++-- * Concurrency And Exception Handling+, threadDelay+, forkIO+, bracket+, bracket_+, throw+, catch+, catches++-- * Generics+, Generic++-- * Functions+, chain+, module Data.Function++-- * Date and Time+, Day (..)+, TimeOfDay (..)+, UTCTime (..)+, LocalTime (..)+, TimeZone (..)+, ZonedTime (..)+, TimeLocale (..)+, DiffTime (..)+, NominalDiffTime (..)+, secondsToDiffTime+, picosecondsToDiffTime+, addUTCTime+, diffUTCTime+, getCurrentTime++, defaultTimeLocale++, toGregorian+, fromGregorian++, formatTime+)+where++import Prelude hiding ( putStr+ , putStrLn+ , readFile+ , writeFile+ , lookup+ , getContents+ , null+ , elem+ , concat+ , filter+ , take+ , drop+ , lines+ , words+ , length+ )+import qualified Prelude+import System.FilePath hiding ( (<.>), isValid )+import System.Directory+import qualified System.IO as IO+import System.IO (stderr, stdout, stdin, Handle)+import Data.Maybe+import Control.Monad+import Control.Applicative hiding ( empty )+import Text.Printf+import Data.Monoid+import Data.Char+import Control.Arrow (left, right, (+++), (|||))+import Data.Foldable hiding (null, elem, concat, length)+import System.Environment+import Control.Concurrent.MVar+import Control.Concurrent.Chan+import Data.IORef+import Control.Monad.State++import Text.Casing+import qualified Data.Text as Text+import qualified Data.Text.IO as Text+import qualified Data.Text.Lazy+import qualified Data.Text.Lazy as LText+import qualified Data.Text.Lazy.IO as LText+import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as LBS+import qualified Data.HashMap.Strict as HashMap+import qualified Data.HashMap.Lazy as LHashMap+import qualified Data.HashSet as HashSet+import qualified Data.ByteString.Base64 as Base64+import qualified Data.Vector as Vector+import Data.Vector (Vector)+import qualified Data.Set as Set+import Data.Set (Set)+import qualified Data.Map as Map+import Data.Map (Map)+import Data.Hashable (Hashable (..))+import Text.StringConvert+import Data.Typeable+import GHC.Generics+import GHC.Exts hiding (toList)+import Data.Data+import Data.Semigroup+import Control.DeepSeq+import qualified Data.List as List+import Control.Lens+import Control.Lens.TH (makeLenses)+import Data.Aeson (ToJSON (..), FromJSON (..), Value, object)+import Data.Aeson.TH (deriveJSON)+import qualified Data.Aeson as JSON+import qualified Data.Aeson.TH as JSON+import Data.Default+import Data.List (foldl')+import Control.Concurrent+import Control.Exception+import Data.Function++import Data.Time++import Language.Haskell.TH.Syntax (Name, Q, Dec)++type Text = Text.Text+type LText = LText.Text+type ByteString = BS.ByteString+type LByteString = LBS.ByteString++empty :: Monoid a => a+empty = mempty++append :: Monoid a => a -> a -> a+append = mappend++concat :: Monoid a => [a] -> a+concat = mconcat++lines :: (FromString a, ToString a) => a -> [a]+lines = map s . Prelude.lines . s++words :: (FromString a, ToString a) => a -> [a]+words = map s . Prelude.words . s++trim :: (FromString a, ToString a) => a -> a+trim = ltrim . rtrim++ltrim :: (FromString a, ToString a) => a -> a+ltrim = s . dropWhile isSpace . s++rtrim :: (FromString a, ToString a) => a -> a+rtrim = s . List.dropWhileEnd isSpace . s++{-#RULES "Text.trim" trim = Text.strip #-}+{-#RULES "LText.trim" trim = Data.Text.Lazy.strip #-}+{-#RULES "Text.ltrim" trim = Text.dropWhile isSpace #-}+{-#RULES "Text.rtrim" trim = Text.dropWhileEnd isSpace #-}+{-#RULES "LText.ltrim" trim = Data.Text.Lazy.dropWhile isSpace #-}+{-#RULES "LText.rtrim" trim = Data.Text.Lazy.dropWhileEnd isSpace #-}++type HashMap = HashMap.HashMap++-- | A lazy hash map. Because 'LHashMap.HashMap' is actually the exact+-- same type as 'HashMap.HashMap', we wrap it in a newtype so that+-- we can tie laziness into the type itself (similar to how it works+-- for 'Text' and 'ByteString').+newtype LHashMap k v = LHashMap { unLHashMap :: LHashMap.HashMap k v }+ deriving (Read, Show, Typeable, Generic, Functor, Foldable, Traversable, Eq, Data, Semigroup, Monoid, NFData, Hashable)++type HashSet = HashSet.HashSet++-- | Types that can be written to / read from file descriptors.+class StringIO a where+ putStr :: a -> IO ()+ putStrLn :: a -> IO ()+ hPutStr :: Handle -> a -> IO ()+ hPutStrLn :: Handle -> a -> IO ()+ readFile :: FilePath -> IO a+ writeFile :: FilePath -> a -> IO ()+ getContents :: IO a+ hGetContents :: Handle -> IO a+ putStrLn str = putStr str >> putStr "\n"+ hPutStrLn h str = hPutStr h str >> hPutStr h "\n"++instance StringIO String where+ putStr = IO.putStr+ putStrLn = IO.putStrLn+ hPutStr = IO.hPutStr+ hPutStrLn = IO.hPutStrLn+ readFile = IO.readFile+ writeFile = IO.writeFile+ getContents = IO.getContents+ hGetContents = IO.hGetContents++instance StringIO Text where+ putStr = Text.putStr+ putStrLn = Text.putStrLn+ hPutStr = Text.hPutStr+ hPutStrLn = Text.hPutStrLn+ readFile = Text.readFile+ writeFile = Text.writeFile+ getContents = Text.getContents+ hGetContents = Text.hGetContents++instance StringIO LText where+ putStr = LText.putStr+ putStrLn = LText.putStrLn+ hPutStr = LText.hPutStr+ hPutStrLn = LText.hPutStrLn+ readFile = LText.readFile+ writeFile = LText.writeFile+ getContents = LText.getContents+ hGetContents = LText.hGetContents++instance StringIO ByteString where+ putStr = BS.putStr+ hPutStr = BS.hPutStr+ readFile = BS.readFile+ writeFile = BS.writeFile+ getContents = BS.getContents+ hGetContents = BS.hGetContents++instance StringIO LByteString where+ putStr = LBS.putStr+ hPutStr = LBS.hPutStr+ readFile = LBS.readFile+ writeFile = LBS.writeFile+ getContents = LBS.getContents+ hGetContents = LBS.hGetContents++-- | Things that support keyed element lookup.+class Lookup m k | m -> k where+ lookup :: k -> m v -> Maybe v+ lookupDef :: v -> k -> m v -> v+ lookupDef d k = fromMaybe d . lookup k++newtype AList k v = AList { unAList :: [(k, v)] }+ deriving (Show, Read, Eq, Ord, Generic, Functor)++instance Eq k => Lookup (AList k) k where+ lookup k = Prelude.lookup k . unAList++class ListLike m a | m -> a where+ intersperse :: a -> m -> m+ take :: Int -> m -> m+ takeEnd :: Int -> m -> m+ drop :: Int -> m -> m+ dropEnd :: Int -> m -> m+ slice :: Int -> Int -> m -> m+ slice offset len = take len . drop offset+ length :: m -> Int+ takeEnd n x = drop (length x - n) x+ dropEnd n x = take (length x - n) x++instance ListLike [a] a where+ intersperse = List.intersperse+ take = List.take+ drop = List.drop+ length = List.length++instance ListLike (Vector a) a where+ intersperse e = Vector.fromList . List.intersperse e . Vector.toList+ take = Vector.take+ drop = Vector.drop+ slice = Vector.slice+ length = Vector.length++instance ListLike Text Char where+ intersperse = Text.intersperse+ take = Text.take . fromIntegral+ drop = Text.drop . fromIntegral+ length = fromIntegral . Text.length++instance ListLike LText Char where+ intersperse = LText.intersperse+ take = LText.take . fromIntegral+ drop = LText.drop . fromIntegral+ length = fromIntegral . LText.length++startsWith :: (Eq a, ListLike a e) => a -> a -> Bool+startsWith haystack needle =+ take (length needle) haystack == needle++endsWith :: (Eq a, ListLike a e) => a -> a -> Bool+endsWith haystack needle =+ takeEnd (length needle) haystack == needle++intercalate :: (Monoid a, Foldable m, ListLike (m a) a) => a -> m a -> a+intercalate s = mconcat . toList . intersperse s++-- | Things that behave like sets.+class SetLike m v | m -> v where+ -- | Conjoin: add an element to a set. For ordered sets, the+ -- end at which the new element is inserted is unspecified.+ conj :: v -> m -> m++ -- | Remove all occurrences of the element from the set.+ remove :: v -> m -> m++ -- | Test if the element is in the set.+ elem :: v -> m -> Bool++ -- | Test if the set is empty.+ null :: m -> Bool++ -- | Convert the set to a list of elements. The ordering is unspecified.+ items :: m -> [v]++ -- | Create a set from a list of elements. Duplicate list elements+ -- may be skipped at the implementation's discretion.+ fromItems :: [v] -> m++ -- | Create a singleton (one-element) set.+ singleton :: v -> m++ -- | Get the number of elements in the set.+ size :: m -> Int++ size = List.length . items+ null = List.null . items++-- | Things that can be filtered+class Filterable m where+ -- | Filter the set to retain only the elements that match the predicate.+ filter :: (v -> Bool) -> m v -> m v++cull :: Filterable m => (v -> Bool) -> m v -> m v+cull = filter . (not .)++-- | Things that behave like key-value dictionaries.+class DictLike m k where+ -- | Add or overwrite an element at a key.+ insert :: k -> v -> m k v -> m k v+ -- | Delete by key+ delete :: k -> m k v -> m k v+ -- | Modify an element at a key+ update :: k -> (v -> Maybe v) -> m k v -> m k v+ -- | Convert to an association list (list of key/value pairs)+ pairs :: m k v -> [(k, v)]+ -- | Convert from an association list (list of key/value pairs)+ fromPairs :: [(k, v)] -> m k v+ -- | Get the keys, discard the values+ keys :: m k v -> [k]+ -- | Get the values, discard the keys+ elems :: m k v -> [v]+ -- | Create a singleton dictionary (just one key-value pair)+ singletonMap :: k -> v -> m k v+ -- | Test whether the dictionary contains a given key+ member :: k -> m k v -> Bool++ keys = map fst . pairs+ elems = map snd . pairs++instance Eq k => DictLike AList k where+ insert k v (AList xs) = AList $ (k,v):xs+ delete k (AList xs) = AList $ filter ((/= k) . fst) xs+ update k f (AList xs) = AList [ (k, fromMaybe v $ f v) | (k, v) <- xs ]+ pairs = unAList+ fromPairs = AList+ singletonMap k v = AList [(k, v)]+ member k = not . null . filter (== k) . keys++instance Lookup [] Int where+ lookup i xs = case drop i xs of+ [] -> Nothing+ (x:_) -> Just x++instance Lookup Vector Int where+ lookup = flip (Vector.!?)++instance (Eq a) => SetLike (Vector a) a where+ conj = Vector.cons+ remove x = Vector.filter (/= x)+ elem = Vector.elem+ null = Vector.null+ items = Vector.toList+ fromItems = Vector.fromList+ singleton = Vector.singleton+ size = Vector.length++instance Filterable Vector where+ filter = Vector.filter++instance (Eq a) => SetLike [a] a where+ conj = (:)+ remove x = filter (/= x)+ elem = List.elem+ null = List.null+ items = id+ fromItems = id+ singleton = (:[])+ size = List.length++instance Filterable [] where+ filter = List.filter++instance (Eq v, Hashable v) => SetLike (HashSet v) v where+ conj = HashSet.insert+ remove = HashSet.delete+ elem = HashSet.member+ null = HashSet.null+ items = HashSet.toList+ fromItems = HashSet.fromList+ singleton = HashSet.singleton+ size = HashSet.size++instance Filterable HashSet where+ filter = HashSet.filter++instance (Eq v, Ord v) => SetLike (Set v) v where+ conj = Set.insert+ remove = Set.delete+ elem = Set.member+ null = Set.null+ items = Set.toList+ fromItems = Set.fromList+ singleton = Set.singleton+ size = Set.size++instance Filterable Set where+ filter = Set.filter++instance (Eq k, Hashable k) => Lookup (HashMap.HashMap k) k where+ lookup = HashMap.lookup++instance (Eq k, Hashable k) => DictLike HashMap.HashMap k where+ insert = HashMap.insert+ delete = HashMap.delete+ update = flip HashMap.update+ pairs = HashMap.toList+ fromPairs = HashMap.fromList+ keys = HashMap.keys+ elems = HashMap.elems+ singletonMap = HashMap.singleton+ member = HashMap.member++instance (Eq k, Hashable k) => SetLike (HashMap k v) (k, v) where+ conj = uncurry insert+ remove = delete . fst+ elem = member . fst+ null = HashMap.null+ items = pairs+ fromItems = fromPairs+ singleton = uncurry singletonMap++instance Filterable (HashMap k) where+ filter = HashMap.filter++instance (Eq k, Ord k) => Lookup (Map.Map k) k where+ lookup = Map.lookup++instance (Eq k, Ord k) => DictLike Map.Map k where+ insert = Map.insert+ delete = Map.delete+ update = flip Map.update+ pairs = Map.toList+ fromPairs = Map.fromList+ keys = Map.keys+ elems = Map.elems+ singletonMap = Map.singleton+ member = Map.member++instance (Eq k, Ord k) => SetLike (Map k v) (k, v) where+ conj = uncurry insert+ remove = delete . fst+ elem = member . fst+ null = Map.null+ items = pairs+ fromItems = fromPairs+ singleton = uncurry singletonMap++instance Filterable (Map k) where+ filter = Map.filter++overLHashMap :: (HashMap k v -> HashMap k v) -> LHashMap k v -> LHashMap k v+overLHashMap f = LHashMap . f . unLHashMap++instance (Eq k, Hashable k) => DictLike LHashMap k where+ insert k v = overLHashMap $ LHashMap.insert k v+ delete k = overLHashMap $ LHashMap.delete k+ update k f = overLHashMap $ LHashMap.update f k+ pairs = LHashMap.toList . unLHashMap+ fromPairs = LHashMap . LHashMap.fromList+ keys = LHashMap.keys . unLHashMap+ elems = LHashMap.elems . unLHashMap+ singletonMap k v = LHashMap (LHashMap.singleton k v)+ member k = LHashMap.member k . unLHashMap++instance (Eq k, Hashable k) => Lookup (LHashMap k) k where+ lookup k = LHashMap.lookup k . unLHashMap++instance (Eq k, Hashable k) => SetLike (LHashMap k v) (k, v) where+ conj = uncurry insert+ remove = delete . fst+ elem = member . fst+ null = LHashMap.null . unLHashMap+ items = pairs+ fromItems = fromPairs+ singleton = uncurry singletonMap++instance Filterable (LHashMap k) where+ filter p = overLHashMap $ LHashMap.filter p++prettyJsonOptions :: JSON.Options+prettyJsonOptions =+ JSON.defaultOptions+ { JSON.fieldLabelModifier = kebab . dropWhile (== '_')+ , JSON.constructorTagModifier = kebab+ , JSON.omitNothingFields = True+ , JSON.sumEncoding = JSON.defaultTaggedObject+ { JSON.tagFieldName = "what"+ , JSON.contentsFieldName = "value"+ }+ }++derivePrettyJSON :: Name -> Q [Dec]+derivePrettyJSON = deriveJSON prettyJsonOptions++asString :: String -> String+asString = id++asText :: Text -> Text+asText = id++asLText :: LText -> LText+asLText = id++asByteString :: ByteString -> ByteString+asByteString = id++asLByteString :: LByteString -> LByteString+asLByteString = id++asHashMap :: HashMap k v -> HashMap k v+asHashMap = id++encodeJSON :: ToJSON a => a -> LByteString+encodeJSON = JSON.encode++decodeJSON :: FromJSON a => LByteString -> Maybe a+decodeJSON = JSON.decode++encodeJSONStrict :: ToJSON a => a -> ByteString+encodeJSONStrict = s . JSON.encode++decodeJSONStrict :: FromJSON a => ByteString -> Maybe a+decodeJSONStrict = JSON.decodeStrict++chain :: Traversable t => t (a -> a) -> a -> a+chain = foldl' (.) id++(~>) :: ToJSON a => Text -> a -> (Text, Value)+(~>) = (JSON..=)++decodeBase64 :: ByteString -> ByteString+decodeBase64 = Base64.decodeLenient++encodeBase64 :: ByteString -> ByteString+encodeBase64 = Base64.encode