# Laziness is not always good

### From HaskellWiki

(Difference between revisions)

(exercise) |
m (Removed extra line-breaks.) |
||

(2 intermediate revisions by 2 users not shown) | |||

Line 1: | Line 1: | ||

− | Generally, since Haskell is a [[Non-strict_semantics|non-strict]] language, |
+ | Generally, since Haskell is a [[Non-strict_semantics|non-strict]] language, you should try to make a function [[maintaining laziness|least strict]]. |

− | you should try to make a function [[maintaining laziness|least strict]]. |
||

This is in many cases the best semantics and the most efficient implementation. |
This is in many cases the best semantics and the most efficient implementation. |
||

However, here is an important exception from the rule: |
However, here is an important exception from the rule: |
||

Line 14: | Line 14: | ||

forall a. mappend a mempty = a |
forall a. mappend a mempty = a |
||

</haskell> |
</haskell> |
||

− | You find that it is not <hask>mappend mempty undefined = undefined</hask>, |
+ | You find that it is not <hask>mappend mempty undefined = undefined</hask>, but <hask>mappend mempty undefined = mempty</hask>. |

− | but <hask>mappend mempty undefined = mempty</hask>. |
||

Is this academic nitpicking or practically relevant? |
Is this academic nitpicking or practically relevant? |
||

− | I think it is the latter one, because a <hask>Monoid</hask> instance implicitly promises |
+ | I think it is the latter one, because a <hask>Monoid</hask> instance implicitly promises that monoid laws can be applied in every case. |

− | that monoid laws can be applied in every case. |
||

A programmer expects that every occurence of <hask>mappend mempty a</hask> can be safely replaced by <hask>a</hask>. |
A programmer expects that every occurence of <hask>mappend mempty a</hask> can be safely replaced by <hask>a</hask>. |
||

You might even create an [[Playing by the rules|optimizer rule]] doing this. |
You might even create an [[Playing by the rules|optimizer rule]] doing this. |
||

− | The above implementation of <hask>mappend</hask> however evaluates its operands lazily, |
+ | The above implementation of <hask>mappend</hask> however evaluates its operands lazily, and this gets lost when the optimization is applied. |

− | and this gets lost when the optimization is applied. |
||

The solution of this issue is to define |
The solution of this issue is to define |
||

Line 39: | Line 39: | ||

== Exercise == |
== Exercise == |
||

− | Find out, whether it would help to define <hask>mempty = undefined</hask>. |
+ | Find out whether it would help to define <hask>mempty = undefined</hask>. |

== See also == |
== See also == |
||

* 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]] |
||

## Latest revision as of 16:21, 21 September 2011

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 theMonoid

()

mempty = () mappend _ _ = ()

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

Remind you:mempty

mappend

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

mappend mempty undefined = undefined

mappend mempty undefined = mempty

Is this academic nitpicking or practically relevant?

I think it is the latter one, because aMonoid

mappend mempty a

a

You might even create an optimizer rule doing this.

The above implementation ofmappend

The solution of this issue is to define

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

and write

mappend (force a) (force b)

mappend a b

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

## [edit] 1 Exercise

Find out whether it would help to definemempty = undefined

## [edit] 2 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