Personal tools

Laziness is not always good

From HaskellWiki

(Difference between revisions)
Jump to: navigation, search
m (delete comma splice)
(space leak and selectors)
Line 48: Line 48:
* Haskell-Cafe on [ Laws and partial values]
* 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]]
* [[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
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:
must be the identity element with respect to
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
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

You might even create an optimizer rule doing this.

The above implementation of
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.

1 Exercise

Find out whether it would help to define
mempty = undefined

2 See also