packages feed

universum-1.0.4: README.md

Universum
=========

[![Build Status](https://travis-ci.org/serokell/universum.svg?branch=master)](https://travis-ci.org/serokell/universum)
[![Windows build status](https://ci.appveyor.com/api/projects/status/github/serokell/universum?branch=master&svg=true)](https://ci.appveyor.com/project/ChShersh/universum)
[![Hackage](https://img.shields.io/hackage/v/universum.svg)](https://hackage.haskell.org/package/universum)
[![Stackage LTS](http://stackage.org/package/universum/badge/lts)](http://stackage.org/lts/package/universum)
[![Stackage Nightly](http://stackage.org/package/universum/badge/nightly)](http://stackage.org/nightly/package/universum)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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.
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`.
* `foldl'` takes a function with its arguments flipped compared with the `base` version.


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`.
* `ToPairs` type class for data types that can be converted to list of pairs.

License
-------

Released under the MIT License.
Copyright (c) 2016, Stephen Diehl, 2016-2017, Serokell