1

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.

duplode
  • 33,731
  • 7
  • 79
  • 150
Hamburguesa66
  • 87
  • 1
  • 7
  • `computeS` does not occur in `IO` so you need to have `let rotated = (computeS $ rot180 v) :: Array F DIM3 Word8` instead of `rotated <- (computeP $ rot180 v) :: IO (Array F DIM3 Word8)`. – Alec Jul 28 '17 at 21:19
  • What is `computeP`, anyway? I can't find anything of that name in the libraries you've quoted. Please always add concrete links to tha hackage haddocks, like this: [`computeS`](http://hackage.haskell.org/package/repa-array-4.2.3.1/docs/Data-Repa-Array-Generic-Load.html#v:computeS). – leftaroundabout Jul 28 '17 at 21:26
  • Ok, i will do it next time. Thanks guys. – Hamburguesa66 Jul 28 '17 at 21:39
  • @leftaroundabout To be fair, `computeP` and `computeS` are sort of at the centre of REPA. [Here](https://hackage.haskell.org/package/repa-3.4.1.2/docs/Data-Array-Repa.html#v:computeP) they are in the main `Data.Array.Repa` module. – Alec Jul 28 '17 at 22:06
  • @leftaroundabout, question is about repa3, while you added a link to repa4 – lehins Aug 02 '17 at 01:20
  • @AlexeyKuleshevich well, that underlines my point – a question should always link to the concrete versions of functions it asks about. Also, `computeP` is apparently obsolete then... – leftaroundabout Aug 02 '17 at 07:13
  • @leftaroundabout, your point was certainly a valid one. It's not that `computeP` is obsolete, it's that repa4 is still in experimental stage and doesn't have that function. Not sure if it does computation in parallel by default or simply doesn't support it, I'll have to figure it out. – lehins Aug 02 '17 at 09:45

1 Answers1

1

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
lehins
  • 9,642
  • 2
  • 35
  • 49