前回はrepaの基本的な使い方を説明しました。それを基に、今回はいよいよrepaの特色である行列演算を行う方法を説明します。

前回の補足

 前回の記事を書いた後にリリースされたrepa 3.2.1.1で、repaのAPIが少し変更されたので補足しておきます。

 ReprクラスはSourceクラスという名前に変更され、Array型は独立した型族からSourceクラスに属する型族に変更されました。

Prelude Data.Array.Repa>  :i Source
class Source r e where
  data family Array r sh e
  extent :: Shape sh => Array r sh e -> sh
  index :: Shape sh => Array r sh e -> sh -> e
  unsafeIndex :: Shape sh => Array r sh e -> sh -> e
  linearIndex :: Shape sh => Array r sh e -> Int -> e
  unsafeLinearIndex :: Shape sh => Array r sh e -> Int -> e
  deepSeqArray :: Shape sh => Array r sh e -> b -> b
        -- Defined in `repa-3.2.1.1:Data.Array.Repa.Base'
instance Source D a -- Defined in `Data.Array.Repa.Repr.Delayed'

 FillableクラスもTragetクラスに変更され、MArr型はMVec型に変更されました。

Prelude Data.Array.Repa.Eval>  :i Target
class Target r e where
  data family MVec r e
  newMVec :: Int -> IO (MVec r e)
  unsafeWriteMVec :: MVec r e -> Int -> e -> IO ()
  unsafeFreezeMVec ::
    sh
    -> MVec r e -> IO (repa-3.2.1.1:Data.Array.Repa.Base.Array r sh e)
  deepSeqMVec :: MVec r e -> a -> a
  touchMVec :: MVec r e -> IO ()
        -- Defined in `repa-3.2.1.1:Data.Array.Repa.Eval.Target'

 また、Fillクラスのクラス名とメソッド名が、それぞれLoadクラスとload*メソッドに変更されました。

Prelude Data.Array.Repa.Eval> :i Load
class (repa-3.2.1.1:Data.Array.Repa.Base.Source r1 e,
       Data.Array.Repa.Shape.Shape sh) => Load r1 sh e where
  loadS ::
    Target r2 e =>
    repa-3.2.1.1:Data.Array.Repa.Base.Array r1 sh e
    -> MVec r2 e -> IO ()
  loadP ::
    Target r2 e =>
    repa-3.2.1.1:Data.Array.Repa.Base.Array r1 sh e
    -> MVec r2 e -> IO ()
        -- Defined in `repa-3.2.1.1:Data.Array.Repa.Eval.Load'

 これらの変更は、「ある配列をソースとして処理を行う」「配列の各要素を読み込み(load)、目的(target)の配列を作成する」といった処理の意図をより明確に示せるようにするためのものです。例えば、map関数やcomputeS関数の型は、処理内容が明確になりました。

map     :: (Shape sh, Source r a)
        => (a -> b) -> Array r sh a -> Array D sh b

computeS 
        :: (Load r1 sh e, Target r2 e)
        => Array r1 sh e -> Array r2 sh e