packages feed

hydrogen-prelude 0.8 → 0.20

raw patch · 7 files changed

Files

CHANGELOG.md view
@@ -1,6 +1,5 @@ ## v0.1 + initial release-+ ***deprecated***  ## v0.1.0.1 + Patch: Modules were not properly exported in Cabal file@@ -15,7 +14,7 @@ + Added CHANGELOG.md to source package  ## v0.2.1-+ Added __++ Added `__` (short hand for `undefined`)  ## v0.3 + Also exports@@ -27,4 +26,81 @@ + New dependency on `hydrogen-version`   + Exports `module Hydrogen.Version` as replacement for `module Data.Version` +## v0.4+*Skipped, bumped to v0.5 to be aligned with other hydrogen packages*++## v0.5++ Deriving instance `Eq` for `ZonedTime`++## v0.6++ New dependencies+  + `cereal` for serialization+  + `strict` for strict io in `Hydrogen.Prelude.IO`++ Also exports+  + `module Data.Dynamic`+  + `module Data.Typeable`++ Added `ShowBox` class (an existentially qualified container type)++## v0.7++ Newly deriving instances+  + `Serialize` for `ZonedTime`+  + `Serialize` for `Version`++## v0.8++ Added `class TMap (tmap)` and `class Has (HasKey, HasValue, (!))`++ Introduced `type List a` as alias for `[a]`++ Also exports+  + `Data.Seq`++ Added the F-Sharp inspired `|>` (which is `flip ($)`)++ Exporting only `Generic` from `GHC.Generics`++ Added `Hydrogen.Prelude.Network`++## v0.9++ Also exports+  + `module Data.Traversable`++ Added `class Container (Contained, (?))`++ `fmap` is exported as `map`++## v0.10++ Added `safeHeadAndTail`, `safeHeadAndTail2`, `firstJust`++ Little documentation improvements++ Added `findFilesRecursively` and `findFilesRecursivelyWithContext`+  in `Hydrogen.Prelude.System`++## v0.11++ Added `nicify` form `Text.Nicify`++ 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,3 +1,312 @@+hydrogen-prelude+================ +[![Build Status](https://travis-ci.org/scravy/hydrogen-prelude.svg?branch=master)](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)++ [`goodies`](#goodies)+  + [`(!)`](#--has-a--a--haskey-a--hasvalue-a)+  + [`(?)`](#--container-a--a--contained-a--bool)+  + [`tmap`](#tmap)+  + [`fmap` vs `map`](#fmap-vs-map)+  + [`__`](#__--a)+  + [`|>`](#fsharps--which-is-flip-)+  + [`safeHead`](#safehead--a--a--a)+  + [`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)+  + [`Hydrogen.Prelude.System`](#hydrogenpreludesystem)+  + [`Hydrogen.Prelude.Network`](#hydrogenpreludenetwork)++ [`FAQ`](#faq)++about+-----++A Prelude that exports much of the standard library (more then `Prelude`), without conflicts. If for example you were to import `Prelude` and `Data.List` or `Data.Foldable` you will run into ambiguous imports (regarding `foldr` for example). This Prelude aims at exporting the most general functions (in this case `foldr` from `Data.Foldable`).++It also pulls in some default packages like `cereal` for serialization and `containers` for data types like `Map` and `Set`. Every datatype exported by this Prelude comes with instances for `Serialize`.++Longs story short, instead of:++    import Prelude hiding (+      all, and, any, concat, concatMap, elem, foldl, foldl1, foldr, foldr1,+      mapM, mapM_, maximum, minimum, notElem, or, product, sequence, sequence_, sum+     )+    import "base" Control.Monad hiding (+      forM, forM_, mapM, mapM_, msum, sequence, sequence_+     )+    import Data.Foldable+    import Data.Traversable+    import Data.List hiding (+      all, and, any, concat, concatMap, elem, find, foldl, foldl', foldl1, foldr, foldr1,+      mapAccumL, mapAccumR, maximum, maximumBy, minimum, minimumBy, notElem, or, product, sum+     )+    +it suffices to:++    import Hydrogen.Prelude++goodies+-------++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.++    [(1, 'a'), (3, 'v')] ! 1  →  'a'++Instances are defined for+++ `Eq k ⇒ [(k, v)]`++ `Ix i ⇒ Array i e` with `HasKey → i`++ `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.++    [1, 2, 4] ? 3  →  False++Instances are defined for+++ `Eq a ⇒ [a]`++ `Ord a ⇒ Set a`++ `Eq a ⇒ Seq a`++ `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).++    tmap succ (3, 4)  →  (4, 5)++Instances are defined for+++ `(a, a)`++ `(a, a, a)`++ `(a, a, a, a)`++ `[a]`++ `Seq a`++ `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 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++The Hydrogen Prelude offers you the functions and datatypes from these modules, all with one import:+++ from [`base`](http://hackage.haskell.org/package/base)+  + `module Prelude`+  + `module Control.Applicative`+  + `module Control.Arrow`+  + `module Control.Monad`+  + `module Data.Bits`+  + `module Data.Bool`+  + `module Data.Char`+  + `module Data.Complex`+  + `module Data.Complex`+  + `module Data.Dynamic`+  + `module Data.Either`+  + `module Data.Fixed`+  + `module Data.Function`+  + `module Data.Foldable`+  + `module Data.Int`+  + `module Data.Ix`+  + `module Data.List`+  + `module Data.Maybe`+  + `module Data.Ord`+  + `module Data.Ratio`+  + `module Data.String`+  + `module Data.Time`+  + `module Data.Traversable`+  + `module Data.Tuple`+  + `module Data.Typeable`+  + `module Data.Word`+  + `module Numeric`+  + `module Text.Printf`+++ from [`array`](http://hackage.haskell.org/package/array)+  + `module Data.Array`+++ from [`cereal`](http://hackage.haskell.org/package/cereal)+  + `module Data.Serialize`+++ from [`containers`](http://hackage.haskell.org/package/containers)+  + `Data.Set`, `Data.Map`, and `Data.Seq`+++ from [`hashable`](http://hackage.haskell.org/package/hashable)+  + `module Data.Hashable`+++ form [`hydrogen-multimap`](http://hackage.haskell.org/package/hydrogen-multimap)+  + `Hydrogen.MultiMap`+++ from [`hydrogen-version`](http://hackage.haskell.org/package/hydrogen-version)+  + `module Hydrogen.Version`+++ from [`regex-tdfa`](http://hackage.haskell.org/package/regex-tdfa)+  + `module Text.Regex.TDFA`+++ from [`time`](http://hackage.haskell.org/package/time)+  + `module Data.Time`+++ from [`transformers`](http://hackage.haskell.org/package/transformers)+  + `module Data.Functor.Identity`+  + `module Data.Functor.Reverse`+++ from [`uuid`](http://hackage.haskell.org/package/uuid)+  + `Data.UUID`+  + `Data.UUID.fromString` as `uuidFromString`+  + `Data.UUID.V4.nextRandom` as `randomUUID`+++### Hydrogen.Prelude.IO+++ from [`base`](http://hackage.haskell.org/package/base)+  + `module Data.IORef`+  + `module Control.Concurret`+  + `module Control.Exception`+  + `module System.IO`+  + `module System.Timeout`+++ from [`strict`](http://hackage.haskell.org/package/strict)+  + strict IO functions `hGetContents'`, `getContents'`, `readFile'`, `interact'`+++### Hydrogen.Prelude.System+++ from [`base`](http://hackage.haskell.org/package/base)+  + `module System.CPUTime`+  + `module System.Environment`+  + `module System.Exit`+  + `module System.Info`+++ from [`directory`](http://hackage.haskell.org/package/directory)+  + `module System.Directory`+++ from [`filepath`](http://hackage.haskell.org/package/filepath)+  + `module System.FilePath`+++ from [`process`](http://hackage.haskell.org/package/process)+  + `module System.Process`+++ from [`random`](http://hackage.haskell.org/package/random)+  + `module System.Random`+++### Hydrogen.Prelude.Network+++ from [`network`](http://hackage.haskell.org/package/network)+  + `module Network`+++FAQ+===++How is some of the *magic* accomplished?+----------------------------------------++Mostly with `XTypeFamilies` and `XStandaloneDeriving`.++So this works only with GHC?+----------------------------++Yes, for now at least.++What is `hydrogen`+------------------++https://www.youtube.com/watch?v=rbBX6aEzEz8  
Setup.hs view
@@ -1,2 +1,4 @@ import Distribution.Simple+ main = defaultMain+
hydrogen-prelude.cabal view
@@ -1,8 +1,8 @@ name:                 hydrogen-prelude-version:              0.8-homepage:             https://scravy.de/hydrogen-prelude/+version:              0.20+homepage:             http://scravy.de/hydrogen-prelude/ synopsis:             Hydrogen Prelude-license:              BSD3+license:              MIT license-file:         LICENSE extra-source-files:   CHANGELOG.md, README.md author:               Julian Fleischer@@ -12,50 +12,59 @@ 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-version >=1.2-                      , network >=2.4.2.2-                      , 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   default-extensions: CPP                       , DeriveDataTypeable+                      , DeriveFoldable                       , DeriveFunctor                       , DeriveGeneric-                      , EmptyCase+                      , DeriveTraversable                       , FlexibleInstances                       , FlexibleContexts                       , GADTs-                      , LambdaCase-                      , MultiWayIf-                      , NegativeLiterals+                      , MultiParamTypeClasses                       , NoImplicitPrelude                       , PackageImports-                      , RankNTypes                       , RecordWildCards                       , ScopedTypeVariables                       , StandaloneDeriving-                      , TupleSections                       , TypeFamilies
src/Hydrogen/Prelude.hs view
@@ -24,9 +24,10 @@   , module Data.Maybe   , module Data.Ord   , module Data.Ratio-  , module Data.Serialize   , module Data.String   , module Data.Time+  , module Data.Time.Calendar.OrdinalDate+  , module Data.Traversable   , module Data.Tuple   , module Data.Typeable   , module Data.Word@@ -35,22 +36,52 @@   , module Text.Printf   , (.&)   , (.|)+  , (.^)   , (=~)   , (=~~)   , (|>)-  , for+  , ($$)+  , ($$$)+  , ($$$$)+  , ($$$$$)+  , (<$$>)+  , (<$$$>)+  , (<$$$$>)+  , (<$$$$$>)   , uuidFromString   , randomUUID   , safeHead+  , safeHeadAndTail+  , safeHeadAndTail2+  , firstJust+  , uncurry3+  , uncurry4+  , uncurry5+  , map   , UUID+  , ByteString+  , LazyByteString+  , Serialize+  , encode+  , encodeLazy+  , decode+  , decodeLazy+  , Binary+  , binaryEncode+  , binaryDecode+  , binaryEncodeFile+  , binaryDecodeFile   , Generic   , List   , Map-  , Set+  , MultiMap   , Seq+  , Set   , ShowBox   , TMap (..)   , Has (..)+  , Container (..)+  , Default (..)   , __   ) where @@ -65,30 +96,44 @@   , foldl1   , foldr   , foldr1+  , map+  , mapM   , mapM_   , maximum   , minimum   , notElem   , or   , product+  , sequence   , sequence_   , sum+#if MIN_VERSION_base(4,6,0)+#else+  , catch+#endif   )  import "base" Control.Applicative import "base" Control.Arrow import "base" Control.Monad hiding (-    forM_+    forM+  , forM_+  , mapM   , mapM_   , msum+  , sequence   , sequence_   )  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@@ -114,9 +159,12 @@   , foldl1   , foldr   , foldr1+  , map+  , mapAccumL+  , mapAccumR   , maximum-  , minimum   , maximumBy+  , minimum   , minimumBy   , notElem   , or@@ -126,14 +174,21 @@ 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+import "base" Data.Traversable import "base" Data.Tuple 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 @@ -143,10 +198,11 @@ import "containers" Data.Map (Map) import qualified "containers" Data.Map as Map import "containers" Data.Set (Set)--- import qualified "containers" Data.Set as Set+import qualified "containers" Data.Set as Set import "containers" Data.Sequence (Seq)--- import qualified "containers" Data.Sequence as Seq +import "hydrogen-multimap" Hydrogen.MultiMap (MultiMap)+import qualified "hydrogen-multimap" Hydrogen.MultiMap as MultiMap import "hydrogen-version" Hydrogen.Version  import "uuid" Data.UUID (UUID)@@ -154,6 +210,18 @@ import qualified "uuid" Data.UUID 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@@ -162,59 +230,197 @@ 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 -(.|), (.&) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)++-----------------------------------------------------------------------+-- 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 ($) -for :: Functor f => f a -> (a -> b) -> f b-for = flip fmap- __ :: a+-- ^ A shorthand for 'undefined'. __ = error "Hydrogen.Prelude.undefined" ++-----------------------------------------------------------------------+-- UUID functions+-----------------------------------------------------------------------+ uuidFromString :: String -> Maybe UUID uuidFromString = Data.UUID.fromString  randomUUID :: IO UUID+-- ^ Produces a random V4 UUID (alias for 'Data.UUID.V4.nextRandom'). randomUUID = Data.UUID.V4.nextRandom -safeHead :: a -> [a] -> a-safeHead d = \case++-----------------------------------------------------------------------+-- 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_ = \z -> case z of     x : _ -> x-    _     -> d+    _     -> default_ +safeHeadAndTail :: a -> [a] -> (a, [a])+safeHeadAndTail default_ = \z -> case z of+    x : xs -> (x, xs)+    _ -> (default_, []) +safeHeadAndTail2 :: a -> a -> [a] -> (a, a, [a])+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+--   (or 'Nothing' if no 'Just' value was produced).+firstJust (f : fs) v = case f v of+    Nothing -> firstJust fs v+    x -> x+firstJust [] _ = Nothing+++-----------------------------------------------------------------------+-- More generic maps+-----------------------------------------------------------------------++map :: Functor f => (a -> b) -> f a -> f b+-- ^ map as it should be: 'fmap'.+map = fmap+ class TMap a where      type Component x@@ -249,15 +455,22 @@     type Component [a] = a     type Transform ((a -> b) -> [a]) = [b] -    tmap = map+    tmap = fmap  instance TMap (Map k v) where      type Component (Map k v) = v     type Transform ((v -> w) -> Map k v) = Map k w -    tmap = Map.map+    tmap = fmap +instance TMap (MultiMap k v) where++    type Component (MultiMap k v) = v+    type Transform ((v -> w) -> MultiMap k v) = MultiMap k w++    tmap = fmap+ instance TMap (Seq a) where      type Component (Seq a) = a@@ -266,27 +479,36 @@     tmap = fmap  +-----------------------------------------------------------------------+-- Verbose `List' type+-----------------------------------------------------------------------+ type List a = [a] ++-----------------------------------------------------------------------+-- Has+-----------------------------------------------------------------------+ class Has a where -    type K a-    type V a+    type HasKey a+    type HasValue a -    (!) :: a -> K a -> V a+    (!) :: a -> HasKey a -> HasValue a   instance Ord k => Has (Map k v) where -    type K (Map k v) = k-    type V (Map k v) = v+    type HasKey (Map k v) = k+    type HasValue (Map k v) = v      (!) = (Map.!)  instance Eq k => Has [(k, v)] where -    type K [(k, v)] = k-    type V [(k, v)] = v+    type HasKey [(k, v)] = k+    type HasValue [(k, v)] = v      list ! key = maybeKey (lookup key list)       where@@ -294,9 +516,124 @@  instance Ix i => Has (Array i e) where -    type K (Array i e) = i-    type V (Array i e) = e+    type HasKey (Array i e) = i+    type HasValue (Array i e) = e      (!) = (Array.!) +instance Ord k => Has (MultiMap k v) where++    type HasKey (MultiMap k v) = k+    type HasValue (MultiMap k v) = [v]++    (!) = flip MultiMap.lookup+++-----------------------------------------------------------------------+-- Container+-----------------------------------------------------------------------++class Container a where++    type Contained a++    (?) :: a -> Contained a -> Bool+++instance Ord a => Container (Set a) where++    type Contained (Set a) = a++    (?) = flip Set.member++instance Eq a => Container [a] where++    type Contained [a] = a++    (?) = flip elem++instance Eq a => Container (Seq a) where++    type Contained (Seq a) = a++    c ? e = any (== e) c++instance Ord k => Container (Map k v) where++    type Contained (Map k v) = k++    (?) = flip Map.member++instance Ord k => Container (MultiMap k v) where++    type Contained (MultiMap k v) = k++    (?) = 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/IO.hs view
@@ -2,7 +2,6 @@     module Hydrogen.Prelude   , module Control.Concurrent   , module Control.Exception-  , module Control.Monad   , module Data.IORef   , module System.IO   , module System.Timeout@@ -18,12 +17,6 @@  import "base" Control.Concurrent import "base" Control.Exception-import "base" Control.Monad hiding (-    forM_-  , mapM_-  , msum-  , sequence_-  )  import "base" System.IO import "base" System.Timeout
src/Hydrogen/Prelude/System.hs view
@@ -1,3 +1,5 @@+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+ module Hydrogen.Prelude.System (     module Hydrogen.Prelude.IO   , module System.CPUTime@@ -8,6 +10,10 @@   , module System.Info   , module System.Process   , module System.Random+  , findFilesRecursively+  , findFilesRecursivelyWithContext+  , escapeFileName+  , unescapeFileName ) where  import Hydrogen.Prelude.IO@@ -20,4 +26,78 @@ import "base" System.Info import "process" System.Process import "random" System.Random++import qualified Data.Set as Set+++findFilesRecursively :: (FilePath -> IO Bool) -> FilePath -> IO [FilePath]+findFilesRecursively f dir =+    map fst <$> findFilesRecursivelyWithContext (\c _ _ -> return c) f () dir+++findFilesRecursivelyWithContext+    :: forall c.+       (c -> FilePath -> [FilePath] -> IO c)  -- ^ update function for current context+    -> (FilePath -> IO Bool)                  -- ^ predicate to filter files+    -> c                                      -- ^ current context+    -> FilePath -> IO [(FilePath, c)]+findFilesRecursivelyWithContext updater predicate context dir = do++    cwd <- getCurrentDirectory+    snd <$> find Set.empty context (cwd </> dir)++  where++    find :: Set FilePath -> c -> FilePath -> IO (Set FilePath, [(FilePath, c)])+    find visited context dir = canonicalizePath dir >>= find'+      where+        find' thisDirectory+          | 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++                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++                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) /= '.'))+++escapeFileName :: String -> String+escapeFileName s = case s of+    ('/' : xs)+        -> '_' : 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` ".-"+++unescapeFileName :: String -> Maybe String+unescapeFileName s = case s of+    ('$' : '$' : a : b : c : d : xs)+        -> (chr <$> hexnum (a : b : c : [d])) `cons` unescapeFileName xs+    ('$' : a : b : xs)+        -> (chr <$> hexnum (a : [b])) `cons` unescapeFileName xs+    ('_' : xs)+        -> pure '/' `cons` unescapeFileName xs+    (x : xs)+        -> pure x `cons` unescapeFileName xs+    [] -> return []+  where+    cons = liftA2 (:)+    hexnum = fmap fst . listToMaybe . readHex