hydrogen-prelude 0.14 → 0.20
raw patch · 6 files changed
Files
- CHANGELOG.md +32/−1
- README.md +50/−1
- Setup.hs +2/−0
- hydrogen-prelude.cabal +33/−28
- src/Hydrogen/Prelude.hs +247/−17
- src/Hydrogen/Prelude/System.hs +19/−19
CHANGELOG.md view
@@ -69,7 +69,38 @@ ## v0.11 + Added `nicify` form `Text.Nicify`-+ Upgraded dependency `hydrogen-version` form `>=1.2` to `>=1.3`++ Upgraded dependency `hydrogen-version` from `>=1.2` to `>=1.3` ## v0.12 + Added `Default`++## v0.13++ _Skipped_++## v0.14++ Aligned with other `hydrogen-*` packages++## v0.15++ Added `Apply`++ Added `uncurry3`, `uncurry4`, `uncurry5`++## v0.16++ Changed `Apply` to use `-XMultiParamTypeClasses` and `-XTypeFamilies`+ for better type inference++ Added `$$`, `$$$`, `$$$$`, `$$$$$` (like `uncurryN`)++ Added `<$$>`, `<$$$>`, `<$$$$>`, `<$$$$$>` (like `<$>` and `uncurryN`)++## v0.17++ Removed instance `MonadPlus m => Default (m a)`.++## v0.18++ Removed dependency on `nicify`++## v0.19++ Removed `Apply` and `Applicator` again++ Lowered dependencies to work with GHC 7.6 and base 4.6 too++## v0.20++ Support for GHC 7.4, 7.6, and 7.8++ Instances for `Serializable` but also for `Binary`+
README.md view
@@ -1,6 +1,8 @@ hydrogen-prelude ================ +[](https://travis-ci.org/scravy/hydrogen-prelude)+ + [`about`](#about) + [`scravy.de/hydrogen-prelude`](http://scravy.de/hydrogen-prelude) + [`hackage.haskell.org/package/hydrogen-prelude`](http://hackage.haskell.org/package/hydrogen-prelude)@@ -15,6 +17,8 @@ + [`ShowBox`](#showbox--forall-a-show-a--a--showbox) + [`.|`, `.&`, `.^`](#----a--bool--a--bool--a--bool) + [`List a`](#type-list-a--a)+ + [`Default a`](#class-default-a)+ + [`Apply a`](#class-apply-a) + [`re-exports`](#re-exports) + [`Hydrogen.Prelude`](#hydrogenprelude) + [`Hydrogen.Prelude.IO`](#hydrogenpreludeio)@@ -54,6 +58,8 @@ Beyond existing functions from well-known standard packages, this prelude defines a few utilities (mostly aimed at unifying functionality across different packages, like `containers` and `array`). +---+ ### `(!) :: Has a ⇒ a → HasKey a → HasValue a` `(!)` is provided for several data types which associate a key and a value.@@ -67,6 +73,8 @@ + `Ord k ⇒ Map k v` with `HasValue → v` + `Ord k ⇒ MultiMap k v` with `HasValue → [v]` +---+ ### `(?) :: Container a ⇒ a → Contained a → Bool` Check whether the element on the right is contained in the collection on the left.@@ -81,6 +89,8 @@ + `Ord k ⇒ Map k v` with `Contained → k` + `Ord k ⇒ MultiMap k v` with `Contained → k` +---+ ### `tmap` A little bit like `fmap` but defined differently on some datatypes (applies e.g. to both components of a tuple).@@ -97,42 +107,81 @@ + `Map k v` + `MultiMap k v` +---+ ### `fmap` vs `map` Hydrogen Prelude exports `fmap` as `map` - the way it ought to be. +---+ ### `__ :: a` A handy shortcut for `undefined`. +---+ ### FSharp's `|>` (which is `flip ($)`) Use it to pipe things from one function to the other, left to right: head xs |> fromEnum |> show +---+ ### `safeHead :: a → [a] → a` The head of the list, or the default given as first argument. safeHead x xs = maybe x head . listToMaybe +---+ ### `ShowBox :: forall a. (Show a) ⇒ a → ShowBox` ### Wrap anything that is showable (can be used to build heterogeneous lists). +---+ ### `.|, .&, .^ :: (a → Bool) → (a → Bool) → (a → Bool)` Combines predicates. filter (isDigit .| isLetter) +---+ ### `type List a = [a]` -A shorthand for the type of lists, if you prefer this more wordy version.+A longhand for the type of lists, if you prefer this more wordy version. +---++### `class Default a` ###++A class that provides the `def` function for default values for types.+Instances of `MonadPlus` automatically have an instance where `def = mzero`.++Default instances for most primitive types are also provided.++---++### `class Apply a` ###++Provides the `*$*` operator which is your all-purpose application operator.+It does uncurrying (if you want to apply a tupel result of a function to+a function that is curryied, works with tupels of up to 5 components) and+also works with `Applicative`, i.e. it also does `fmap . uncurry`:++ data Operator = Operator Value OperatorType Value++ parseInfixOperation :: Parser (Value, OperatorType, Value)++ ... Operator *$* parseInfixOperation ...+ re-exports ----------+ ### Hydrogen.Prelude
Setup.hs view
@@ -1,2 +1,4 @@ import Distribution.Simple+ main = defaultMain+
hydrogen-prelude.cabal view
@@ -1,5 +1,5 @@ name: hydrogen-prelude-version: 0.14+version: 0.20 homepage: http://scravy.de/hydrogen-prelude/ synopsis: Hydrogen Prelude license: MIT@@ -12,33 +12,43 @@ cabal-version: >=1.14 source-repository head- type: git- location: https://github.com/scravy/hydrogen-prelude+ type: git+ location: https://github.com/scravy/hydrogen-prelude +flag explicitText+ library exposed-modules: Hydrogen.Prelude , Hydrogen.Prelude.IO , Hydrogen.Prelude.Network , Hydrogen.Prelude.System- build-depends: base ==4.7.*- , array ==0.5.*- , cereal ==0.4.*- , containers ==0.5.*- , directory ==1.2.*- , filepath ==1.3.*- , hashable ==1.2.*- , hydrogen-multimap ==0.1- , hydrogen-version >=1.3- , network >=2.4.2.2- , nicify- , process ==1.2.*- , random ==1.0.*- , regex-base ==0.93.*- , regex-tdfa ==1.2.*- , strict ==0.3.*- , time ==1.4.*- , transformers ==0.3.*- , uuid ==1.3.*+ build-depends: base >=4.5 && <5+ , array >=0.4+ , binary >=0.5.1+ , bytestring >=0.9.2.1+ , cereal >=0.4.1.1+ , containers >=0.4.2.1+ , directory >=1.1+ , filepath >=1.3+ , hashable >=1.1+ , hydrogen-multimap >=0.3+ , hydrogen-version >=1.4+ , network >=2.3+ , process >=1.1.0.1+ , random >=1.0.1.1+ , regex-base >=0.93.1+ , regex-tdfa >=1.2+ , strict >=0.3+ , text >=0.11.2+ , time >=1.4+ , transformers >=0.3+ , uuid >=1.3+ if impl(ghc <= 7.6)+ build-depends: ghc-prim+ , text <1.2.0.4+ if impl(ghc >= 7.6)+ build-depends: binary >=0.7+ hs-source-dirs: src ghc-options: -Wall default-language: Haskell2010@@ -48,18 +58,13 @@ , DeriveFunctor , DeriveGeneric , DeriveTraversable- , EmptyCase , FlexibleInstances , FlexibleContexts , GADTs- , LambdaCase- , MultiWayIf- , NegativeLiterals+ , MultiParamTypeClasses , NoImplicitPrelude , PackageImports- , RankNTypes , RecordWildCards , ScopedTypeVariables , StandaloneDeriving- , TupleSections , TypeFamilies
src/Hydrogen/Prelude.hs view
@@ -24,7 +24,6 @@ , module Data.Maybe , module Data.Ord , module Data.Ratio- , module Data.Serialize , module Data.String , module Data.Time , module Data.Time.Calendar.OrdinalDate@@ -41,15 +40,37 @@ , (=~) , (=~~) , (|>)+ , ($$)+ , ($$$)+ , ($$$$)+ , ($$$$$)+ , (<$$>)+ , (<$$$>)+ , (<$$$$>)+ , (<$$$$$>) , uuidFromString , randomUUID- , nicify , safeHead , safeHeadAndTail , safeHeadAndTail2 , firstJust+ , uncurry3+ , uncurry4+ , uncurry5 , map , UUID+ , ByteString+ , LazyByteString+ , Serialize+ , encode+ , encodeLazy+ , decode+ , decodeLazy+ , Binary+ , binaryEncode+ , binaryDecode+ , binaryEncodeFile+ , binaryDecodeFile , Generic , List , Map@@ -86,6 +107,10 @@ , sequence , sequence_ , sum+#if MIN_VERSION_base(4,6,0)+#else+ , catch+#endif ) import "base" Control.Applicative@@ -103,8 +128,12 @@ import "array" Data.Array hiding ((!)) import qualified "array" Data.Array as Array +import "binary" Data.Binary (Binary)+import qualified "binary" Data.Binary as Binary import "base" Data.Bits hiding (bitSize) import "base" Data.Bool+import "bytestring" Data.ByteString (ByteString)+import qualified "bytestring" Data.ByteString.Lazy as LazyByteString import "base" Data.Char import "base" Data.Complex import "base" Data.Dynamic@@ -145,7 +174,8 @@ import "base" Data.Maybe import "base" Data.Ord import "base" Data.Ratio-import "cereal" Data.Serialize+import "cereal" Data.Serialize (Serialize)+import qualified "cereal" Data.Serialize as Serialize import "base" Data.String import "time" Data.Time import "time" Data.Time.Calendar.OrdinalDate@@ -154,13 +184,16 @@ import "base" Data.Typeable import "base" Data.Word +#if MIN_VERSION_base(4,6,0) import "base" GHC.Generics (Generic)+#else+import "ghc-prim" GHC.Generics (Generic)+#endif import "base" Numeric import "base" Text.Printf import "regex-tdfa" Text.Regex.TDFA-import "nicify" Text.Nicify (nicify) import "containers" Data.Map (Map) import qualified "containers" Data.Map as Map@@ -178,6 +211,17 @@ import qualified "uuid" Data.UUID.V4 +-----------------------------------------------------------------------+-- Lazy type aliases+-----------------------------------------------------------------------++type LazyByteString = LazyByteString.ByteString+++-----------------------------------------------------------------------+-- Generic instances+-----------------------------------------------------------------------+ deriving instance Eq ZonedTime deriving instance Generic Day deriving instance Generic LocalTime@@ -186,39 +230,129 @@ deriving instance Generic UniversalTime deriving instance Generic ZonedTime ++-----------------------------------------------------------------------+-- Serialize & Binary instances+-----------------------------------------------------------------------+ instance Serialize Day-instance Serialize LocalTime-instance Serialize TimeOfDay+instance Binary Day+ instance Serialize TimeZone+instance Binary TimeZone+ instance Serialize UniversalTime+instance Binary UniversalTime+ instance Serialize Version+instance Binary Version++#if MIN_VERSION_base(4,7,0)+instance Serialize LocalTime+instance Binary LocalTime++instance Serialize TimeOfDay+instance Binary TimeOfDay+ instance Serialize ZonedTime+instance Binary ZonedTime instance Serialize (Fixed E12) where- put (MkFixed int) = put int+ put (MkFixed int) = Serialize.put int - get = MkFixed <$> get+ get = MkFixed <$> Serialize.get +instance Binary (Fixed E12) where+ put (MkFixed int) = Binary.put int++ get = MkFixed <$> Binary.get+#endif+ instance Serialize UUID where - put uuid = do- let p = putWord32be- (w1, w2, w3, w4) = Data.UUID.toWords uuid- p w1 >> p w2 >> p w3 >> p w4+ put uuid = p w1 >> p w2 >> p w3 >> p w4+ where+ p = Serialize.putWord32be+ (w1, w2, w3, w4) = Data.UUID.toWords uuid - get = let g = getWord32be in liftM4 Data.UUID.fromWords g g g g- + get = liftM4 Data.UUID.fromWords g g g g+ where+ g = Serialize.getWord32be++-- instance Binary UUID is already provided by UUID package+++-----------------------------------------------------------------------+-- Data.Serialize+-----------------------------------------------------------------------++encode :: Serialize a => a -> ByteString+-- ^ Encode a value using binary serialization to a strict ByteString.+encode = Serialize.encode++encodeLazy :: Serialize a => a -> LazyByteString+-- ^ Encode a value using binary serialization to a lazy ByteString.+encodeLazy = Serialize.encodeLazy++decode :: Serialize a => ByteString -> Either String a+-- ^ Decode a value from a strict ByteString, reconstructing the+-- original structure.+decode = Serialize.decode++decodeLazy :: Serialize a => LazyByteString -> Either String a+-- ^ Decode a value from a lazy ByteString, reconstructing the+-- original structure.+decodeLazy = Serialize.decodeLazy+++-----------------------------------------------------------------------+-- Data.Binary+-----------------------------------------------------------------------++binaryEncode :: Binary a => a -> LazyByteString+-- ^ Encode a value using binary serialisation to a lazy ByteString.+binaryEncode = Binary.encode++binaryDecode :: Binary a => LazyByteString -> a+-- ^ Decode a value from a lazy ByteString, reconstructing the+-- original structure.+binaryDecode = Binary.decode++binaryEncodeFile :: Binary a => FilePath -> a -> IO ()+-- ^ Lazily serialise a value to a file.+binaryEncodeFile = Binary.encodeFile++binaryDecodeFile :: Binary a => FilePath -> IO a+-- ^ Decode a value from a file. In case of errors, error will be+-- called with the error message.+binaryDecodeFile = Binary.decodeFile+++-----------------------------------------------------------------------+-- ShowBox+-----------------------------------------------------------------------+ data ShowBox where ShowBox :: forall a. (Show a) => a -> ShowBox instance Show ShowBox where show (ShowBox a) = show a ++-----------------------------------------------------------------------+-- Composition of boolean functions+-----------------------------------------------------------------------+ (.|), (.&), (.^) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool) f .| g = \x -> f x || g x f .& g = \x -> f x && g x f .^ g = \x -> f x /= g x ++-----------------------------------------------------------------------+-- Nice shorthands & operators+-----------------------------------------------------------------------+ (|>) :: a -> (a -> b) -> b -- ^ @flip ('$')@ (|>) = flip ($)@@ -227,6 +361,11 @@ -- ^ A shorthand for 'undefined'. __ = error "Hydrogen.Prelude.undefined" ++-----------------------------------------------------------------------+-- UUID functions+-----------------------------------------------------------------------+ uuidFromString :: String -> Maybe UUID uuidFromString = Data.UUID.fromString @@ -234,26 +373,36 @@ -- ^ Produces a random V4 UUID (alias for 'Data.UUID.V4.nextRandom'). randomUUID = Data.UUID.V4.nextRandom ++-----------------------------------------------------------------------+-- Safe functions+-----------------------------------------------------------------------+ safeHead :: a -- ^ The default value for the case of the empty list. -> [a] -- ^ The list. -> a -- ^ Returns the head of the list or the default value.-safeHead default_ = \case+safeHead default_ = \z -> case z of x : _ -> x _ -> default_ safeHeadAndTail :: a -> [a] -> (a, [a])-safeHeadAndTail default_ = \case+safeHeadAndTail default_ = \z -> case z of x : xs -> (x, xs) _ -> (default_, []) safeHeadAndTail2 :: a -> a -> [a] -> (a, a, [a])-safeHeadAndTail2 d1 d2 = \case+safeHeadAndTail2 d1 d2 = \z -> case z of x : y : xs -> (x, y, xs) x : xs -> (x, d2, xs) xs -> (d1, d2, xs) ++-----------------------------------------------------------------------+-- firstJust+-----------------------------------------------------------------------+ firstJust :: [a -> Maybe b] -> a -> Maybe b -- ^ Applies a bunch of functions on a given value, -- returns the first result that is not Nothing@@ -263,6 +412,11 @@ x -> x firstJust [] _ = Nothing ++-----------------------------------------------------------------------+-- More generic maps+-----------------------------------------------------------------------+ map :: Functor f => (a -> b) -> f a -> f b -- ^ map as it should be: 'fmap'. map = fmap@@ -325,8 +479,17 @@ tmap = fmap +-----------------------------------------------------------------------+-- Verbose `List' type+-----------------------------------------------------------------------+ type List a = [a] ++-----------------------------------------------------------------------+-- Has+-----------------------------------------------------------------------+ class Has a where type HasKey a@@ -366,6 +529,10 @@ (!) = flip MultiMap.lookup +-----------------------------------------------------------------------+-- Container+-----------------------------------------------------------------------+ class Container a where type Contained a@@ -404,6 +571,69 @@ (?) = flip MultiMap.member +-----------------------------------------------------------------------+-- Default+-----------------------------------------------------------------------+ class Default a where def :: a++instance Default Int where def = 0+instance Default Int8 where def = 0+instance Default Int16 where def = 0+instance Default Int32 where def = 0+instance Default Int64 where def = 0+instance Default Word8 where def = 0+instance Default Word16 where def = 0+instance Default Word32 where def = 0+instance Default Word64 where def = 0+instance Default Integer where def = 0++instance Default Bool where def = False+instance Default [a] where def = []+instance Default (Maybe a) where def = Nothing+++-----------------------------------------------------------------------+-- Apply / curry operators+-----------------------------------------------------------------------++infixr 0 $$+infixr 0 $$$+infixr 0 $$$$+infixr 0 $$$$$++($$) :: (a -> b -> z) -> (a, b) -> z+($$) = uncurry++($$$), uncurry3 :: (a -> b -> c -> z) -> (a, b, c) -> z+uncurry3 f (a, b, c) = f a b c+($$$) = uncurry3++($$$$), uncurry4 :: (a -> b -> c -> d -> z) -> (a, b, c, d) -> z+uncurry4 f (a, b, c, d) = f a b c d+($$$$) = uncurry4++($$$$$), uncurry5 :: (a -> b -> c -> d -> e -> z) -> (a, b, c, d, e) -> z+uncurry5 f (a, b, c, d, e) = f a b c d e+($$$$$) = uncurry5+++infixl 4 <$$>+infixl 4 <$$$>+infixl 4 <$$$$>+infixl 4 <$$$$$>++(<$$>) :: Functor f => (a -> b -> z) -> f (a, b) -> f z+(<$$>) = (<$>) . uncurry++(<$$$>) :: Functor f => (a -> b -> c -> z) -> f (a, b, c) -> f z+(<$$$>) = (<$>) . uncurry3++(<$$$$>) :: Functor f => (a -> b -> c -> d -> z) -> f (a, b, c, d) -> f z+(<$$$$>) = (<$>) . uncurry4++(<$$$$$>) :: Functor f => (a -> b -> c -> d -> e -> z) -> f (a, b, c, d, e) -> f z+(<$$$$$>) = (<$>) . uncurry5+
src/Hydrogen/Prelude/System.hs view
@@ -49,25 +49,25 @@ where find :: Set FilePath -> c -> FilePath -> IO (Set FilePath, [(FilePath, c)])- find visited context dir = do+ find visited context dir = canonicalizePath dir >>= find'+ where+ find' thisDirectory+ | Set.member thisDirectory visited = return (Set.empty, [])+ | otherwise = do - thisDirectory <- canonicalizePath dir- if | Set.member thisDirectory visited -> return (Set.empty, [])- | otherwise -> do+ allFiles <- map (dir </>) <$> getDirectoryContents dir+ theFiles <- filterFiles allFiles+ theDirs <- filterM isDir allFiles+ context' <- updater context dir theFiles - allFiles <- map (dir </>) <$> getDirectoryContents dir- theFiles <- filterFiles allFiles- theDirs <- filterM isDir allFiles- context' <- updater context dir theFiles+ let visited' = Set.insert thisDirectory visited+ f (visited, files) dir = do+ (visited', files') <- find visited context' dir+ return (visited', files' : files) - let visited' = Set.insert thisDirectory visited- f (visited, files) dir = do- (visited', files') <- find visited context' dir- return (visited', files' : files)+ (visited'', files') <- foldM f (visited', []) theDirs - (visited'', files') <- foldM f (visited', []) theDirs- - return (visited'', concat (zip theFiles (repeat context') : files'))+ return (visited'', concat (zip theFiles (repeat context') : files')) filterFiles = filterM (\x -> liftM2 (&&) (doesFileExist x) (predicate x)) isDir x = liftM2 (&&) (doesDirectoryExist x) (return (head (takeFileName x) /= '.'))@@ -77,10 +77,10 @@ escapeFileName s = case s of ('/' : xs) -> '_' : escapeFileName xs- (x : xs) ->- if | isSafeChar x -> x : escapeFileName xs- | ord x <= 255 -> '$' : printf "%02X" (ord x) ++ escapeFileName xs- | otherwise -> "$$" ++ printf "%04X" (ord x) ++ escapeFileName xs+ (x : xs)+ | isSafeChar x -> x : escapeFileName xs+ | ord x <= 255 -> '$' : printf "%02X" (ord x) ++ escapeFileName xs+ | otherwise -> "$$" ++ printf "%04X" (ord x) ++ escapeFileName xs [] -> [] where isSafeChar x = isAscii x && isAlphaNum x || x `elem` ".-"