8

Data.Vector.* パッケージを使用して Haskell でこのようなことをしようとしていますが、どこから始めればよいかわかりません。私はHaskellの初心者で、特定のコアコンセプトをほとんど理解していません(しかし、私はそこに到達しています)。

私がやろうとしていることは、次の C コードでほぼ表現できます。

float *arrA = /* initialized to array of length n */;
float *arrB = /* initialized to array of length n */;
for (i = 1; i < n; i++) {
  for (j = 0; j < n - i; j++) {
    arrB[j] = someFn(i, j, arrA[j], arrB[j+1])
  }
  float *p = arrA;
  arrA = arrB;
  arrB = p;
}
return arrA[0];

注意点:

  • パフォーマンス上の理由から配列を再利用しますが、次の反復で必要な値を踏みにじるのを避けるために2つ必要です
  • 配列が交換される
  • 内側のループの上限は、外側のループの反復ごとに変化します

あなたが提供するかもしれないどんな助けも大歓迎です。

4

1 に答える 1

20

これはばかげた仕事です

C を Haskell に直接変換するのはばかげています。以前に有料でやったことがありますが、スムーズに、または迅速に進みません。タスクを記述し、ターゲット言語で慣用的なスタイルで実装する方がはるかに優れています。アルゴリズムの英語の説明を提供すると、質の高い回答が得られる可能性が高くなります。

コンパイル可能なコードを投稿してください

質問を投稿するときは、コンパイルされていることを確認してください。

HaskellでCを書く方法ではなく、Haskellを学ぶ

特に、命令型から関数型、可変型から不変型、厳密型から遅延型、明示的なキャストから明示的なキャスト、手動で管理されたメモリからガベージ コレクトされたメモリなど、境界を越える場合は特にそうです。あなたはこれらすべての分断を越えています。

あなたの仕事が Haskell を学ぶことであるなら、あなたは間違ったところから始めています。あなたのタスクが Haskell で変更可能なベクトル/配列を学習することである場合は、ニュアンスを理解するために基礎をもっと知る必要があります。あなたの仕事が、配列のサポートが不十分であるために Haskell を罵倒することである場合、Roman がやって来て Vector パッケージを作成する前に、あなたは本当に簡単にそれをすることができたでしょう - これは私の言い方です: HaskellArrayの見た目だけを見ないでくださいsでVector

OK OK、解決策は何ですか?

Vector配列にはパッケージを使用し、変更可能な操作にはモナドSTを使用します (最初の箇条書き):

import qualified Data.Vector.Unboxed.Mutable as M
import qualified Data.Vector.Unboxed as V
import Control.Monad.ST
import Control.Monad

メイン関数は 2 つのベクトルを取り、float を返します。配列への変更可能な参照を取得することから始めthaw、単純な折り畳みを使用して、配列参照を反転できるようにします。

someFunc :: V.Vector Float -> V.Vector Float -> Float
someFunc arrA arrB = runST $ do
        -- Obtain mutable copies of the arrays
        mA <- V.thaw arrA 
        mB <- V.thaw arrB
        (mA', mB') <- foldM op (mA, mB) [1..n-1] -- for(i = 1 ; i < n; i++)
        M.read mA' 0
 where
 n = min (V.length arrA) (V.length arrB)

内側の for ループは に含まれていopます。配列から単純な読み取りを実行し、新しい値を書き込むだけです。タプルで 2 つの配列を返す必要があります。タプルは反復ごとに反転され、可変ポインター (2 番目のポイント) の同じセマンティクスが取得されます。

 op (mA, mB) i = do
        forM_ [0..n-i-1] $ \j -> do
                v1 <- M.read mA j
                v2 <- M.read mB (j+1)
                M.write mB j (someFn i j v1 v2)
        return (mB, mA)

3番目のポイントと一致して、内側のループ境界は外側のループに基づいて変化します。

実行可能なプログラムをコンパイルできるように、main を含めます。

someFn i j f1 f2 = f1 + fromIntegral i + fromIntegral j - f2

main = print $ someFunc (V.fromList [1..10]) (V.fromList [0..9])

これは教育目的のみです。私はこれをテストしていません。道徳的にはCと同じはずですが、ループで1つずれているか、その他の些細な違いがある可能性があります。

于 2012-07-14T03:20:33.447 に答える