[Haskell-cafe] How to write fast for loops

Daniel Fischer daniel.is.fischer at googlemail.com
Sun Apr 27 01:32:12 UTC 2014


On Saturday 26 April 2014, 22:40:50, Niklas Hambüchen wrote:
> As you probably now, `forM_ [1..n]` is incredibly slow in Haskell due to
> lack of list fusion [1];

It's not the lack of list fusion per se. If you have a

forM_ [a .. b] $ \n -> do stuff

where the type is Int, GHC is perfectly capable of eliminating the list and 
rewriting it to a loop (usually on par with a hand-written loop, although the 
core you get from a hand-written loop often is smaller and nicer to look at).

The problem is that you use the same list multiple times, and GHC thinks "hey, 
let me re-use that", so it gets floated to the top-level, and the inner "loop" 
really uses the list, which apart from the `case`s on the list forces it to 
use boxed 'Int's instead of Int#. Then the boxed Ints need to be unboxed to be 
used, oops.

If you manage to conceal the fact that the lists are the same from GHC, it 
eliminates the lists and you get fast code also with forM_.

In your matmult example, using

forM_ [k-k .. _SIZE-1] $ \j -> do ...

does the trick for GHC-7.0 to 7.8.

That is of course a brittle workaround, future GHCs might rewrite the k-k to 0 
and share the list again.

> a manually written loop is 10x faster.
> 
> How do you people work around this?

Do the idiomatic thing and write a loop ;)

> 
> [1]: https://ghc.haskell.org/trac/ghc/ticket/8763

Cheers,
Daniel


More information about the Haskell-Cafe mailing list