I am trying this REPA library, and i want to process an image in both ways, parallel and sequentially.
I can read the image (with other library, DevIL) and process it with computeP (parallel). Here is the code (is from a example on the wiki of haskell).
import Foreign.Ptr
import System.Environment
import Data.Word
import Data.Array.Repa hiding ((++))
import Data.Array.Repa.IO.DevIL
import Data.Array.Repa.Repr.ForeignPtr
main :: IO ()
main = do
[f] <- getArgs
(RGB v) <- runIL $ readImage f
rotated <- (computeP $ rot180 v) :: IO (Array F DIM3 Word8)
runIL $ writeImage ("flip-"++f) (RGB rotated)
rot180 :: (Source r e) => Array r DIM3 e -> Array D DIM3 e
rot180 g = backpermute e flop g
where
e@(Z :. x :. y :. _) = extent g
flop (Z :. i :. j :. k) =
(Z :. x - i - 1 :. y - j - 1 :. k)
Now i want to do it sequentially changing "computeP" with "computeS". But, when i try to compile it, this error appears:
Couldn't match expected type ‘IO (Array F DIM3 Word8)’
with actual type ‘Array r20 DIM3 Word8’
In a stmt of a 'do' block:
rotated <- (computeS $ rot180 v) :: IO (Array F DIM3 Word8)
As you can probably guess, i am new at functional programming. I dont know why this error is happening. Any help would be great.
Thanks in advance.
You are doing everything almost right. The error you are getting is due to the fact that computeP
is monadic, while computeS
is not. If you compare their type signatures closely the difference that is biting you is the Monad m
restriction and return type m (Array r2 sh e)
for computeP
vs (Array r2 sh e)
for computeS
. So long story short, just change
rotated <- (computeP $ rot180 v) :: IO (Array F DIM3 Word8)
to:
let rotated = (computeS $ rot180 v) :: (Array F DIM3 Word8)
The reason why parallel computation in Repa must be monadic has to do partially with lazyness, but mostly with Repa's inability to deal with nested parallelism. Sequential property of a Monad
solves it for the most part:
rotated1 <- (computeP $ rot180 v) :: IO (Array F DIM3 Word8)
rotated2 <- (computeP $ rot180 rotated1) :: IO (Array F DIM3 Word8)
Using do
notation above (and the fact that computeP
uses deepSeqArray
under the hood) makes sure rotated1
is evaluated before getting to second call to computeP
. But since computeS
doesn't use Repa's parallel scheduler it doesn't have that issue, thus doesn't need to use that property of a Monad
and this code will work just fine:
let rotated1 = computeS (rot180 v) :: Array F DIM3 Word8
rotated2 = computeS (rot180 rotated1) :: Array F DIM3 Word8