あなたがやりたいことをする組み込みの機能はないと思います。しかし、これらのプリミティブを使用すると、タスクに命令型コードを記述できるはずです。そして、それが十分に一般的であるならば、あなたはそれを純粋なコードでさえ使うことができるはずですcreate
。私はそれが次のようなものになると思います(スケッチだけ、テストされていません):
imapInto :: (PrimMonad m, Unbox a) => (MVector (PrimState m) a -> Int -> a) -> MVector (PrimState m) a -> MVector (PrimState m) a -> m ()
imapInto f d s = go 0
where
go i = when (i < length d) $ write d i (f s i) >> go (i+1)
ただし、マッピング関数のタイプは奇妙に思えます。意味じゃないのa -> Int -> a
?次に、上記のコードにいくつかの小さな変更が必要になります。
アップデート
上記の関数の更新バージョンとともに、使用例を次に示します。最小限の調整は、m
型コンストラクターをマッパー関数に追加することでした。
module Main where
import qualified Data.Vector.Unboxed.Mutable as MV
import qualified Data.Vector.Unboxed as U
import Control.Monad (forM_)
import Control.Monad.Primitive
imapInto :: (PrimMonad m, MV.Unbox a)
=> (MV.MVector (PrimState m) a -> Int -> m a)
-> MV.MVector (PrimState m) a
-> MV.MVector (PrimState m) a
-> m ()
imapInto f d s = forM_ [0..MV.length s - 1] $ \i -> do
v <- f s i
MV.write d i v
main = do
-- Create two vectors
v1 <- MV.replicate 10 1
v2 <- MV.new 10
-- Map v1 into v2 using function mapper defined below
imapInto mapper v2 v1
-- Print the source and the result
uv1 <- U.unsafeFreeze v1
uv2 <- U.unsafeFreeze v2
print $ U.toList uv1 -- [1,1,1,1,1,1,1,1,1,1]
print $ U.toList uv2 -- [0,1,2,3,4,5,6,7,8,9]
where
-- Mapper reads a value from the vector and multiplies it by its index
mapper v i = fmap (*i) $ MV.read v i
あなたは初心者なので、私はできるだけシンプルにしようとしました。何かがはっきりしないかどうか尋ねてください。
ご覧のとおり、私はLouisのコメントを利用し、forM_
関数を使用しimapInto
てさらに単純forM_
にmapM_
しました(引数を入れ替えたものです)。for
これで、命令型言語からの通常のループのように見えます。また、私が言ったように、マッピング関数の型をからに変更し(MVector (PrimState m) a -> Int -> a)
ました(MVector (PrimState m) a -> Int -> m a)
。これが必要なのは、モナドの外側で可変ベクトル(ここでは最初のパラメーターとして渡される)では多くのことができないためです。しかし、モナド内ではそれを使って何でもできます。ここでは、i
-番目の要素を読み取り、それを。で乗算していi
ます。
このバージョンの関数では、マッピング関数内からソースベクトルを使用して何でも実行できることに注意してください。これを必要とせず、それ自体i
と組み合わせて-th要素のみを使用するi
場合は、これをさらに単純化できます。
imapInto' :: (PrimMonad m, MV.Unbox a, MV.Unbox b)
=> (a -> Int -> b)
-> MV.MVector (PrimState m) b
-> MV.MVector (PrimState m) a
-> m ()
imapInto' f d s = forM_ [0..MV.length s - 1] $ \i -> do
v <- MV.read s i
MV.write d i (f v i)
ここで、マッピング関数は純粋でi
あり、ベクトル自体ではなく、最初の引数として-番目の要素のみを取ります。また、このバージョンを一般化したので、最初のベクトルを別のタイプのベクトルにマップできるため、ソースベクトルと宛先ベクトルが同じタイプである必要はありません。これは、以前のバージョンでも実行できることです。