To be more specific, I have the following innocuous-looking little Repa 3 program:
{-# LANGUAGE QuasiQuotes #-}
import Prelude hiding (map, zipWith)
import
computeP
is the new force
.
In Repa 3 you need to use computeP
everywhere you would have used force
in Repa 2.
The Laplace example from repa-examples is similar to what you're doing. You should also use cmap
instead of plain map
in your blur
function. There will be a paper explaining why on my homepage early next week.
The new representation type parameters don't automagically force when needed (it's probably a hard problem to do that well) - you still have to force manually. In Repa 3 this is done with the computeP function:
computeP
:: (Monad m, Repr r2 e, Fill r1 r2 sh e)
=> Array r1 sh e -> m (Array r2 sh e)
I personally really don't understand why it's monadic, because you can just as well use Monad Identity:
import Control.Monad.Identity (runIdentity)
force
:: (Repr r2 e, Fill r1 r2 sh e)
=> Array r1 sh e -> Array r2 sh e
force = runIdentity . computeP
So, now your output
function can be rewritten with appropriate forcing:
output img = map cast . f . blur . f . blur . f . blur . f $ grey
where ...
with an abbreviation f
using a helper function u
to aid type inference:
u :: Array U sh e -> Array U sh e
u = id
f = u . force
With these changes, the speedup is quite dramatic - which is to be expected, as without intermediate forcing each output pixel ends up evaluating much more than is necessary (the intermediate values aren't shared).
Your original code:
real 0m25.339s
user 1m35.354s
sys 0m1.760s
With forcing:
real 0m0.130s
user 0m0.320s
sys 0m0.028s
Tested with a 600x400 png, the output files were identical.