3

これはこの質問に関連しています:

可変ベクトルをどこから始めればよいかわからない

1つのベクトルから値を取得し、それらを変換して、結果を2番目のベクトルに入れる関数を作成するにはどうすればよいですか?具体的には、ソース配列のすべてのインデックスを反復処理し、そのインデックスと配列を関数に渡してから、関数の結果を別の配列に格納する必要があります。

署名は次のようになります。

imapInto :: (PrimMonad m, Unbox a) => (MVector (PrimState m) a -> Int -> a) -> MVector (PrimState m) a -> MVector (PrimState m) a  -> m ()

そして、このようなものと呼ばれるでしょう:

import Data.Vector.Unboxed.Mutable MV

...
let dst = MV.replicate 10 0.0 in
let src = MV.replicate 10 1.0 in
imapInto (\src' i -> (src' * 2.0)) dst src
...

これにより、src内のすべての要素に2が乗算され、結果がdstに入れられ、状態単位が生成されます。

4

2 に答える 2

5

あなたがやりたいことをする組み込みの機能はないと思います。しかし、これらのプリミティブを使用すると、タスクに命令型コードを記述できるはずです。そして、それが十分に一般的であるならば、あなたはそれを純粋なコードでさえ使うことができるはずです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あり、ベクトル自体ではなく、最初の引数として-番目の要素のみを取ります。また、このバージョンを一般化したので、最初のベクトルを別のタイプのベクトルにマップできるため、ソースベクトルと宛先ベクトルが同じタイプである必要はありません。これは、以前のバージョンでも実行できることです。

于 2012-07-18T20:05:57.857 に答える
1

たとえば、可変ベクトルはまったく必要ありません。以下のテストされていないコードの行に沿って使用mapできます。generate

import Data.Vector.Unboxed as V
import Data.Vector.Unboxed.Mutable as M

double :: V.Vector Int -> V.Vector Int
double = V.map (*2)

また、インデックスを使用する場合:

addIndex = V.imap (\element idx -> element + idx)

不変のベクトルを作成した後、unsafeThaw(このベクトルへの他の参照がないことがわかっていると仮定して)MVectorO(1)でを取得するために使用できます。したがって、最終的な「imapInto」は次のようになります。

imapInto :: some constraints => (V.Vector a -> Int -> b) -> V.Vector a -> M.Vector b
imapInto op v = V.unsafeThaw (V.imap op v)

呼び出し中ではなく、呼び出し前に結果ベクトルを本当に割り当てたい場合はimapInto、Vladimirの回答を参照してください。

于 2012-07-19T02:56:32.820 に答える