• Declarative (thanks to Pattern-Matching with implicit binding and destructuring)
• Even side-effecting `IO` operations are but a description of what to do (eventually).
• Assumes no guarantee of certain order of evaluation. So-called Normal Order of evaluation. Like it is in a cell.
• When performed.
• The result of evaluation of the `Main.main` pure function is a protein-like structure to be executed by the runtime.
• Technically - a type-checked description of a state-machine (a protein-like structure) to be ran by the runtime.

• Equational Semantics (referential transparency)
• Functions are defined as equations where the left hand side equals the right hand side.
• Evaluation is done by rewriting of expressions - by substituting equal for equal after recursively applying predefined reduction rules. Like Maths.
• Function defined by pattern-matching can be used of each sub-definition independently.
• Statically Typed (at the cost of forced homogeneity of conditionals, product-types and recursive-types)
• Every expression (which is reducible to a value) has a type which is determined at compile-time.
• All the types composed together by function application have to be match up (to be consistent).
• Compiler rejects the code which is not type-checked (prevents violations of contracts/discipline). Contradictions do not exist.
• Pure Functional (ultimately, a program is a single referentially-transparnt expression returned by the `main` function)
• Every function is a function in the mathematical sense (i.e., "pure").
• Haskell runtime runs compiled (desugared) code of this expression, eventually performing all the side-effects and `IO` operations
• Even side-effecting `IO` operations are but a descriptions of what to do, produced by pure code.
• It is easy to fuse chains of functions together (making pipelines using function composition).
• Lazy (so-called Normal Order of evaluation or call-by-name, on-demand)
• Every subexpression in implicitly wrapped into a thunk, which is type-tagged in the static environment.
• Functions don't evaluate their arguments - they are passed as expressions (thunks).
• Gives the ability to write control constructs (such as if/else) just by writing normal functions. (a-la macros which do not evaluate - only rewrite!)
• Using expression in definition of itseves - `(==)` (the one I’m defining). When eventually it would be used it will be already defined!
```instance Eq Point where
(Pt x y) == (Pt x' y')   =   x == x' && y == y'
```
• Homogeneous conditionals: `if-then-else` (a syntactic sugar for a `case` expression)
• In a lazy language conditional could be viewed as a function has type `Bool->a->a->a`.
• Short Circuiting is in every expression, due to lazyness.
• Homogeneous lists, tables (maps).
• Tuples and Records (sum-types) for heterogeneous data.
• Immutability allows decomposition back to the parts (atoms) and reuse of the parts without any concerns such as locking (referential transparency)
• Pattern-matching decomposes and rebind the parts of structures (destructuring). Each part could be safely passed (referenced) everywhere.
• Parametric polymorphism - generalize (quantify)
• An implicit parameter (a context) which is a value of an actual type.
• Type-classes (ad-hoc polymorphism) - a named set of interfaces
• Generalize - define a set of interfaces - define what it takes to be a `_____`
• Specialize - provide implementations - what it takes to be a `_____` (implement an interface constrained by the type-class)
• The type a is of the class `Eq` if it implements the function `(==)` that takes two arguments of type a and returns a `Bool`.

Haskell's I/O system is built around a somewhat daunting mathematical foundation: the monad. However, understanding of the underlying monad theory is not necessary to program using the I/O system. Rather, monads are a conceptual structure into which I/O happens to fit.

Monad is an abstraction for general notion of transition from one state to another. Semantically they are explicit transitions from one state to another in an state-machine which is what every program is.

## Side Effects

So called "actions", usually instances of a `Monad`, are descriptions of side-effects which will be performed eventually by the runtime.

"Actions" don't do anything until they are sequenced appropriately using a do-notation expression (a syntactic sugar), which implicitly serializes actions using nesting of function calls (this is how a function composition is actually implemented) - the only way to ensure the evaluation order in a lazy language - by producing a single expression of nested function application (like `\x -> \y -> x + y`, which, unsurprisingly, looks like currying) to be eventually evaluated.

The Haskell runtime runs the `main` function to get this description of all your effects, and then runs the effects per your instructions.

## Unnecessary wrapping

Haskell in the hands of narcissistic idiots is famous for unnecessary wrapping of everything into everything - unnecessary type-classes, more and more general monads, etc. Tooling is not an exception.

```\$ stack ghci --with-ghc intero
```