universum 1.0.0 → 1.0.1
raw patch · 6 files changed
+331/−14 lines, 6 filesdep ~basedep ~bytestringdep ~containers
Dependency ranges changed: base, bytestring, containers, criterion, deepseq, ghc-prim
Files
- CHANGES.md +6/−0
- README.md +285/−0
- src/Universum/Base.hs +1/−1
- src/Universum/Exception.hs +26/−0
- src/Universum/List/Reexport.hs +1/−1
- universum.cabal +12/−12
CHANGES.md view
@@ -1,3 +1,9 @@+1.0.1+=====++* [#100](https://github.com/serokell/universum/issues/100):+ Add `bug` function = `impureThrow`.+ 1.0.0 =====
+ README.md view
@@ -0,0 +1,285 @@+Universum+=========++[](https://travis-ci.org/serokell/universum)+[](https://hackage.haskell.org/package/universum)+[](http://stackage.org/lts/package/universum)+[](http://stackage.org/nightly/package/universum)+[](https://opensource.org/licenses/MIT)++A custom prelude used in Serokell.++What is this?+-------------++This README contains introduction to `Universum` and a tutorial on how to use it.++Structure of this tutorial+--------------------------++This tutorial has several parts:++1. Philosophy and motivation.+2. How to use `universum`.+3. Changes in `Prelude` (some gotchas).+4. Already known things that weren't in `Prelude` brought into scope.+5. New things added.++This is not a tutorial on _Haskell_, and not even a tutorial on each function. For the detailed+documentation of every function with examples and usages see+[_Haddock documentation_](http://hackage.haskell.org/package/universum).++Why another custom Prelude?+---------------------------++### Motivation++In [Serokell](https://github.com/serokell/), we want to be as much productive as possible.+That's why we are using [_Haskell_](https://haskell-lang.org/). This choice of language implies+that we're restricted to use [`Prelude`](http://hackage.haskell.org/package/base-4.9.1.0/docs/Prelude.html):+implicit import of basic functions, type classes and data types. But the default `Prelude`+[is considered to be not so good](https://news.ycombinator.com/item?id=8002749)+due to some historical reasons.++This is why we decided to use a better tool. Hopefully _Haskell_ provides us with ability+to replace default `Prelude` with some alternative. All we need to do is to implement+new basic set of defaults. But we don't intend to implement everything from scratch.+There're already plenty of [preludes](https://guide.aelve.com/haskell/alternative-preludes-zr69k1hc).+After some hot long discussions our team decided to base our custom prelude on+[`protolude`](https://github.com/sdiehl/protolude). If you're not familiar with it,+you can read [a tutorial about `protolude`](http://www.stephendiehl.com/posts/protolude.html).++The next section explains why we have made this choice and what we are willing to do.+This tutorial doesn't cover the differences from `protolude`. Instead, it explains how Universum is different from custom `Prelude`.++### Main goals++While creating and maintaining a custom prelude, we are pursuing the following goals:++1. Avoid all [partial functions](https://www.reddit.com/r/haskell/comments/5n51u3/why_are_partial_functions_as_in_head_tail_bad/).+ We like [total](http://mathworld.wolfram.com/TotalFunction.html) and exception-free functions.+ You can still use some [_unsafe_](https://github.com/serokell/universum/blob/master/src/Unsafe.hs)+ functions but they are not exported by default.+2. Use more efficient [string representations](https://www.reddit.com/r/haskell/comments/29jw0s/whats_wrong_with_string/).+ `String` type is crushingly inefficient. All our functions either try to be polymorphic over string+ types, or use [`Text`](http://hackage.haskell.org/package/text-1.2.2.1/docs/Data-Text.html)+ as the default string type. `String` type alias is still reexported, because the community+ is evolving slowly, some libraries still use `String` type. But we recommend to avoid `String`!+3. Don't reinvent the wheel. We're not trying to rebuild whole type hierarchy from scratch,+ as it's done in [`classy-prelude`](https://github.com/snoyberg/mono-traversable).+ Instead, we reexport common and well-known things from `base` and some other+ libraries used in everyday production programming in _Haskell_.+ > **Note**: well, we did end up inventing something new.+4. Export more useful and commonly used functions. [Hello, my name is Dmitry. I was+ coding _Haskell_ for 3 years but still hoogling which module `liftIO` comes from.](https://twitter.com/magnars/status/834683466130345984)+ Things like `liftIO`, `ReaderT` type, `MVar`-related functions have unambiguous names,+ are used in almost every non-trivial project, and it's really tedious to import them+ manually every time.++Unlike `protolude`, we are:++1. Not trying to be as general as possible (thus we don't export much from+ [`GHC.Generics`](https://github.com/sdiehl/protolude/blob/41710698eedc66fb0bfc5623d3c3a672421fbab5/src/Protolude.hs#L365)).+2. Not trying to maintain every version of `ghc` compiler (only the+ [latest 3](https://github.com/serokell/universum/blob/b6353285859e9ed3544bddbf55d70237330ad64a/.travis.yml#L15)+3. Trying to make writing production code easier (see+ [enhancements and fixes](https://github.com/serokell/universum/issues)).++How to use Universum+----------++Okay, enough philosophy. If you want to just start using `universum` and+explore it with the help of compiler, set everything up according to the instructions below.++Disable the built-in prelude at the top of your file:++```haskell+{-# LANGUAGE NoImplicitPrelude #-}+```++Or directly in your project `.cabal` file, if you want to use in every module by default:++```haskell+default-extensions: NoImplicitPrelude+```++Then add the following import to your modules:++```haskell+import Universum+```++If you're using [Emacs](https://www.gnu.org/software/emacs/), you can+[modify your configs](https://github.com/serokell/universum/issues/8#issuecomment-276444879)+a little bit if you don't want to type `import Universum` manually every time.+++Gotchas+-------++* `id` is renamed to `identity` (because it's nice to be able to use `id` as a variable name).+* `head`, `tail`, `last`, `init` work with `NonEmpty a` instead of `[a]`.+* Safe analogue for `head` function: `safeHead :: [a] -> Maybe a`.+* `undefined` triggers a compiler warning, which is probably not what you want. Either use `throwIO`, `Except`, or `error`.+* `map` is `fmap` now.+* `sortOn` is available without import. This function efficiently sorts a list based on some+ property of its elements (e.g. `sortOn length` would sort elements by length).+* Functions `sum` and `product` are strict now, which makes them more efficient.+* If you try to do something like `putStrLn "hi"`, you'll get an error message if+ `OverloadedStrings` is enabled – it happens because the compiler doesn't know what+ type to infer for the string. Use `putText` in this case.+* Since `show` doesn't come from `Show` anymore, you can't write `Show` instances easily.+ Either use autoderived instances or+ [`Buildable`](https://github.com/serokell/universum/blob/f2ccf8afd862e37ccd204c0ef9efde48a05c2d29/src/Universum.hs#L144).+* You can't call some `Foldable` methods over `Maybe` and some other types.+ `Foldable` generalization is useful but+ [potentially error-prone](https://www.reddit.com/r/haskell/comments/60r9hu/proposal_suggest_explicit_type_application_for/).+ Instead we created our own fully compatible with `Foldable`+ [`Container` type class](https://github.com/serokell/universum/blob/b6353285859e9ed3544bddbf55d70237330ad64a/src/Universum/Container/Class.hs#L180)+ but that restricts the usage of functions like `length` over `Maybe`, `Either`, `Identity` and tuples.+ We're also using _GHC 8_ feature of+ [custom compile-time errors](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#custom-compile-time-errors)+ to produce+ [more helpful messages](https://github.com/serokell/universum/blob/54a742c10720f11c739f2d268365d723924b83a9/src/Containers.hs#L474).+* As a consequence of previous point, some functions like `traverse_`, `forM_`, `sequenceA_`, etc.+ are generalized over `Container` type classes.+* `error` takes `Text`.+++Things that you were already using, but now you don't have to import them explicitly+--------------------------------------------------------------------------++### Commonly used libraries++First of all, we reexport some generally useful modules: `Control.Applicative`,+`Data.Traversable`, `Data.Monoid`, `Control.DeepSeq`, `Data.List`, and lots of others.+Just remove unneeded imports after importing `Universum` (GHC should tell you which ones).++Then, some commonly used types: `Map/HashMap/IntMap`, `Set/HashSet/IntSet`, `Seq`, `Text` and `ByteString`+(as well as synonyms `LText` and `LByteString` for lazy versions).++`liftIO` and `MonadIO` are exported by default. A lot of functions are generalized to `MonadIO`.++`deepseq` is exported. For instance, if you want to force deep evaluation of some value (in IO),+you can write `evaluateNF a`. WHNF evaluation is possible with `evaluateWHNF a`.++We also reexport big chunks of these libraries: `mtl`, `stm`, `microlens`, `microlens-mtl`.++[`Bifunctor`](http://hackage.haskell.org/package/base-4.9.1.0/docs/Data-Bifunctor.html)+type class with useful instances is exported.++* `first` and `second` functions apply a function to first/second part of a tuple (for tuples).+* `bimap` takes two functions and applies them to first and second parts respectively.++### Text++We export `Text` and `LText`, and some functions work with `Text` instead of `String` –+specifically, IO functions (`readFile`, `putStrLn`, etc) and `show`. In fact, `show`+is polymorphic and can produce strict or lazy `Text`, `String`, or `ByteString`.+Also, `toS` can convert any string type to any string type, but you can use `toText`, `toByteString`, `toString` functions to convert to any specific type.++### Debugging and `undefined`s++`trace`, `traceM`, `traceShow`, etc. are available by default. GHC will warn you+if you accidentally leave them in code, however (same for `undefined`).++We also have `data Undefined = Undefined` (which, too, comes with warnings).++### Exceptions++We use [`safe-exceptions`](https://github.com/fpco/safe-exceptions)+library for exceptions handling. Don't import `Control.Exceptions`+module explicitly. Instead use functionality from `safe-exceptions`+provided by `universum` or import `Control.Exceptions.Safe` module.++What's new?+-----------++Finally, we can move to part describing the new cool features we bring with `universum`.++* `uncons` splits a list at the first element.+* `ordNub` and `sortNub` are _O(n log n)_ versions of `nub` (which is quadratic)+ and `hashNub` and `unstableNub` are almost _O(n)_ versions of `nub`.+* `(&)` – reverse application. `x & f & g` instead of `g $ f $ x` is useful sometimes.+* `pretty` and `prettyL` for converting `Buildable` into `Text` (can be used instead of `show`).+* `whenM`, `unlessM`, `ifM`, `guardM` are available and do what you expect+ them to do (e.g. `whenM (doesFileExist "foo")`).+* Very generalized version of `concatMapM`, too, is available and does what expected.+* `readMaybe` and `readEither` are like `read` but total and give either+ `Maybe` or `Either` with parse error.+* `when(Just|Nothing|Left|Right|NotEmpty)[M][_]`+ let you conditionally execute something. Before:++ ```haskell+ case mbX of+ Nothing -> return ()+ Just x -> ... x ...+ ```++ After:++ ```haskell+ whenJust mbX $ \x ->+ ... x ...+ ```++* `for_` for loops. There's also `forM_` but `for_` looks a bit nicer.++ ```haskell+ for_ [1..10] $ \i -> do+ ...+ ```++* `andM`, `allM`, `anyM`, `orM` are monadic version of corresponding functions from `base`.+* Type operator `$` for writing types like `Maybe $ Either String $ Maybe Int`.+* `Each` type family. So this:++ ```haskell+ f :: Each [Show, Read] [a, b] => a -> b -> String+ ```++ translates into this:++ ```haskell+ f :: (Show a, Show b, Read a, Read b) => a -> b -> String+ ```++* `With` type operator. So this:++ ```haskell+ a :: With [Show, Read] a => a -> a+ ```++ translates into this:++ ```haskell+ a :: (Show a, Read a) => a -> a+ ```++* Variadic composition operator `(...)`. So you can write:++ ```haskell+ ghci> (show ... (+)) 1 2+ "3"+ ghci> show ... 5+ "5"+ ghci> (null ... zip5) [1] [2] [3] [] [5]+ True+ ghci> let process = map (+3) ... filter+ ghci> process even [1..5]+ [5,7]+ ```++* Conversions between `Either` and `Maybe` like `rightToMaybe` and `maybeToLeft`+ with clear semantic.+* `using(Reader|State)[T]` functions as aliases for `flip run(Reader|State)[T]`.+* [`One` type class](https://github.com/serokell/universum/blob/master/src/Containers.hs#L473)+ for creating singleton containers. Even monomorhpic ones like `Text`.+* `evaluateWHNF` and `evaluateNF` functions as clearer and lifted aliases for+ `evaluate` and `evaluate . force`.++License+-------++Released under the MIT License.+Copyright (c) 2016, Stephen Diehl, 2016-2017, Serokell
src/Universum/Base.hs view
@@ -74,7 +74,7 @@ import Data.Void (Void, absurd, vacuous) #endif -import GHC.Base (String, asTypeOf, maxInt, minInt, ord, seq, (++))+import GHC.Base (String, asTypeOf, maxInt, minInt, ord, seq) import GHC.Enum (Bounded (..), Enum (..), boundedEnumFrom, boundedEnumFromThen) import GHC.Exts (Constraint, FunPtr, Ptr) import GHC.Float (Double (..), Float (..), Floating (..))
src/Universum/Exception.hs view
@@ -7,6 +7,10 @@ module Universum.Exception ( module Control.Exception.Safe+#if ( __GLASGOW_HASKELL__ >= 800 )+ , Bug (..)+ , bug+#endif , note ) where @@ -18,6 +22,28 @@ import Control.Applicative (Applicative (pure)) import Control.Monad.Except (MonadError, throwError) import Data.Maybe (Maybe, maybe)++#if ( __GLASGOW_HASKELL__ >= 800 )+import Data.List ((++))+import GHC.Show (Show)+import GHC.Stack (CallStack, HasCallStack, callStack, prettyCallStack)++import qualified Control.Exception.Safe as Safe (displayException, impureThrow, toException)++-- | Type that represents exceptions used in cases when a particular codepath+-- is not meant to be ever executed, but happens to be executed anyway.+data Bug = Bug SomeException CallStack+ deriving (Show)++instance Exception Bug where+ displayException (Bug e cStack) = Safe.displayException e ++ "\n"+ ++ prettyCallStack cStack++-- | Generate a pure value which, when forced, will synchronously+-- throw the exception wrapped into 'Bug' data type.+bug :: (HasCallStack, Exception e) => e -> a+bug e = Safe.impureThrow (Bug (Safe.toException e) callStack)+#endif -- To suppress redundant applicative constraint warning on GHC 8.0 -- | Throws error for 'Maybe' if 'Data.Maybe.Nothing' is given.
src/Universum/List/Reexport.hs view
@@ -15,7 +15,7 @@ genericReplicate, genericSplitAt, genericTake, group, inits, intercalate, intersperse, isPrefixOf, iterate, permutations, repeat, replicate, reverse, scanl, scanr, sort, sortBy, sortOn, splitAt, subsequences, tails, take, takeWhile,- transpose, unfoldr, unzip, unzip3, zip, zip3, zipWith)+ transpose, unfoldr, unzip, unzip3, zip, zip3, zipWith, (++)) #if ( __GLASGOW_HASKELL__ >= 800 ) import Data.List.NonEmpty (head, init, last, tail)
universum.cabal view
@@ -1,6 +1,6 @@ name: universum-version: 1.0.0-cabal-version: >=1.10+version: 1.0.1+cabal-version: >=1.18 build-type: Simple license: MIT license-file: LICENSE@@ -15,8 +15,8 @@ category: Prelude author: Stephen Diehl, @serokell tested-with: GHC ==7.10.3 GHC ==8.0.1 GHC ==8.0.2 GHC ==8.2.2-extra-source-files:- CHANGES.md+extra-doc-files: CHANGES.md+ README.md source-repository head type: git@@ -65,10 +65,10 @@ Universum.VarArg build-depends: base >=4.8 && <5,- bytestring >=0.10.8.1,- containers >=0.5.7.1,- deepseq >=1.4.2.0,- ghc-prim >=0.5.0.0,+ bytestring >=0.10.8.2,+ containers >=0.5.10.2,+ deepseq >=1.4.3.0,+ ghc-prim >=0.5.1.1, hashable >=1.2.6.1, microlens >=0.4.8.1, microlens-mtl >=0.1.11.0,@@ -92,11 +92,11 @@ type: exitcode-stdio-1.0 main-is: Main.hs build-depends:- base >=4.9.1.0 && <5,+ base >=4.10.1.0 && <5, universum -any,- containers >=0.5.7.1,- criterion >=1.1.4.0,- deepseq >=1.4.2.0,+ containers >=0.5.10.2,+ criterion >=1.2.6.0,+ deepseq >=1.4.3.0, hashable >=1.2.6.1, mtl >=2.2.1, semigroups >=0.18.3,