[Haskell-cafe] lengthOP rewrite rules

wren ng thornton wren at freegeek.org
Thu Dec 18 22:03:59 EST 2008


Luke Palmer wrote:
> This does not answer your question, but you can solve this problem without
> rewrite rules by having length return a lazy natural:
> 
>    data Nat = Zero | Succ Nat
> 
> And defining lazy comparison operators on it.

And if you want to go that route, then see Data.List.Extras.LazyLength 
from list-extras[1]. Peano integers are quite inefficient, but this 
library does the same transform efficiently.

[1] http://hackage.haskell.org/cgi-bin/hackage-scripts/package/list-extras


> Of course you cannot replace usages of Prelude.length.  But I am really not
> in favor of rules which change semantics, even if they only make things less
> strict.  My argument is the following.  I may come to rely on such
> nonstrictness as in:
> 
>   bad xs = (length xs > 10, length xs > 20)
> 
> bad [1..] will return (True,True).  However, if I do an obviously
> semantics-preserving refactor:
> 
>   bad xs = (l > 10, l > 20)
>   where
>   l = length xs
> 
> My semantics are not preserved: bad [1..] = (_|_, _|_)   (if/unless the
> compiler is clever, in which case my semantics depend on the compiler's
> cleverness which is even worse)

Data.List.Extras.LazyLength does have rewrite rules to apply the lazy 
versions in place of Prelude.length where it can. My justification is 
two-fold. First is that for finite lists the semantics are identical but 
the memory behavior is strictly better. Second is that for non-finite 
lists the termination behavior is strictly better.

It's true that refactoring can disable either point, and that can alter 
semantics in the latter case. Since the module is explicit about having 
these rules, I would say that users should remain aware of the fact that 
they're taking advantage of them or they should use the explicit 
lengthBound or lengthCompare functions instead.

-- 
Live well,
~wren


More information about the Haskell-Cafe mailing list