残念ながら、現在、ボックス化されていない配列が特定のタイプで使用可能であることを要求するコンテキストを作成することはできません。定量化された制約は許可されていません。ただし、実行しようとしていることは引き続き実行できます(タイプ固有のコードバージョンがあるという追加の利点があります)。長い関数の場合は、繰り返されるコードができるだけ小さくなるように、一般的な式を分割してみてください。 。
{-# LANGUAGE FlexibleContexts, ScopedTypeVariables #-}
module AccumST where
import Control.Monad
import Control.Monad.ST
import Data.Array.Unboxed
import Data.Array.ST
import Data.Array.IArray
-- General one valid for all instances of Num.
-- accumST :: forall a. (IArray UArray a, Num a) => [a] -> Int -> a
accumST :: forall a. (IArray UArray a, Num a) => [a] -> Int -> a
accumST vals = (!) . runSTArray $ do
arr <- newArray (0, length vals) 0 :: (Num a) => ST s (STArray s Int a)
forM_ (zip vals [1 .. length vals]) $ \(val, i) ->
readArray arr (i - 1)
>>= writeArray arr i . (+ val)
return arr
accumSTFloat vals = (!) . runSTUArray $ do
arr <- newArray (0, length vals) 0 :: ST s (STUArray s Int Float)
forM_ (zip vals [1 .. length vals]) $ \(val, i) ->
readArray arr (i - 1)
>>= writeArray arr i . (+ val)
return arr
accumSTDouble vals = (!) . runSTUArray $ do
arr <- newArray (0, length vals) 0 :: ST s (STUArray s Int Double)
forM_ (zip vals [1 .. length vals]) $ \(val, i) ->
readArray arr (i - 1)
>>= writeArray arr i . (+ val)
return arr
{-# RULES "accumST/Float" accumST = accumSTFloat #-}
{-# RULES "accumST/Double" accumST = accumSTDouble #-}
Generic Unboxedバージョン(これは機能しません)には、次のような型制約があります。
accumSTU :: forall a. (IArray UArray a, Num a,
forall s. MArray (STUArray s) a (ST s)) => [a] -> Int -> a
次のように簡略化できます。
-- accumST :: forall a. (IArray UArray a, Num a) => [a] -> Int -> a
accumST :: forall a. (IArray UArray a, Num a) => [a] -> Int -> a
accumST vals = (!) . runSTArray $ do
arr <- newArray (0, length vals) 0 :: (Num a) => ST s (STArray s Int a)
accumST_inner vals arr
accumST_inner vals arr = do
forM_ (zip vals [1 .. length vals]) $ \(val, i) ->
readArray arr (i - 1)
>>= writeArray arr i . (+ val)
return arr
accumSTFloat vals = (!) . runSTUArray $ do
arr <- newArray (0, length vals) 0 :: ST s (STUArray s Int Float)
accumST_inner vals arr
accumSTDouble vals = (!) . runSTUArray $ do
arr <- newArray (0, length vals) 0 :: ST s (STUArray s Int Double)
accumST_inner vals arr
{-# RULES "accumST/Float" accumST = accumSTFloat #-}
{-# RULES "accumST/Double" accumST = accumSTDouble #-}