# Difference between revisions of "Laziness is not always good"

m (delete comma splice) |
(space leak and selectors) |
||

Line 48: | Line 48: | ||

* Haskell-Cafe on [http://www.haskell.org/pipermail/haskell-cafe/2009-January/054261.html Laws and partial values] |
* Haskell-Cafe on [http://www.haskell.org/pipermail/haskell-cafe/2009-January/054261.html Laws and partial values] |
||

+ | * Haskell-Cafe on a space leak caused by [http://www.haskell.org/pipermail/haskell-cafe/2010-June/079444.html the garbage collector that did not recognize a selector-like function call] |
||

* [[Maintaining laziness]] |
* [[Maintaining laziness]] |
||

## Revision as of 10:12, 27 June 2010

Generally, since Haskell is a non-strict language,
you should try to make a function least strict.
This is in many cases the best semantics and the most efficient implementation.
However, here is an important exception from the rule:
Consider the `Monoid`

instance of the null type `()`

:

```
mempty = ()
mappend _ _ = ()
```

These functions are least strict, but have a subtle problem:
They do not generally satisfy the monoid laws.
Remind you: `mempty`

must be the identity element with respect to `mappend`

:

```
forall a. mappend mempty a = a
forall a. mappend a mempty = a
```

You find that it is not `mappend mempty undefined = undefined`

,
but `mappend mempty undefined = mempty`

.
Is this academic nitpicking or practically relevant?
I think it is the latter one, because a `Monoid`

instance implicitly promises
that monoid laws can be applied in every case.
A programmer expects that every occurence of `mappend mempty a`

can be safely replaced by `a`

.
You might even create an optimizer rule doing this.
The above implementation of `mappend`

however evaluates its operands lazily,
and this gets lost when the optimization is applied.

The solution of this issue is to define

```
mempty = ()
mappend () () = ()
force :: () -> ()
force _ = ()
```

and write

```
mappend (force a) (force b)
```

instead of `mappend a b`

.

If you find that example too academic, you can choose any other data type with one constructor instead.

## Exercise

Find out whether it would help to define `mempty = undefined`

.

## See also

- Haskell-Cafe on Laws and partial values
- Haskell-Cafe on a space leak caused by the garbage collector that did not recognize a selector-like function call
- Maintaining laziness