I want to implement an algorithm using the ST
monad and STUArray
s, and I want it to be able to work with both Float
and Double
data.
I'll demonstrate on a simpler example problem: calculating a memoized scanl (+) 0
(I know it can be solved without STUArray
, just using as example).
{-# LANGUAGE FlexibleContexts, ScopedTypeVariables #-}
import Control.Monad
import Control.Monad.ST
import Data.Array.Unboxed
import Data.Array.ST
accumST :: forall a. (IArray UArray a, Num a) => [a] -> Int -> a
accumST vals = (!) . runSTUArray $ do
arr <- newArray (0, length vals) 0 :: ST s (STUArray s Int a)
forM_ (zip vals [1 .. length vals]) $ \(val, i) ->
readArray arr (i - 1)
>>= writeArray arr i . (+ val)
return arr
This fails with:
Could not deduce (MArray (STUArray s) a (ST s)) from the context ()
arising from a use of 'newArray'
Possible fix:
add (MArray (STUArray s) a (ST s)) to the context of
an expression type signature
or add an instance declaration for (MArray (STUArray s) a (ST s))
I can't apply the suggested "Possible fix". Because I need to add something like (forall s. MArray (STUArray s) a (ST s))
to the context, but afaik that's impossible..
Unforunately, you can't currently create a context that requires that an unboxed array be available for a specific type. Quantified Constraints aren't allowed. However, you can still accomplish what you're trying to do, (with the added advantage of having type-specific code versions.) For Longer functions, you could try to split out common expressions so that the repeated code is as small as possible.
The Generic Unboxed version (which doesn't work) would have a type constraint like the following:
You could simplify as follows: