2

さて、使用していた関数に固定変数があるという問題を解決していました。その問題に配列を使用するという考えがありました。そこで、作成中の関数と同じ固定変数を持つ配列を使用することを考えましたが、固定変数を持つ配列を作成する方法がわかりません。次のことを試しましたが、効果がありませんでした:

rearrange ::  [Int] -> [a] -> [a]

rearrange l la = elems (f 1 posarr)    
  where
    b = length l
    listarr :: Array Int Int
    listarr = listArray (1,b) l
    arra :: Array Int  c
    arra = listArray (1,b) la
    posarr :: Array Int  c
    posarr = listArray (1,b) la
    f i posarr
      | (b < i) = posarr
      | otherwise = f (i+1) (posarr // [(listarr!i,arra!i)] )

私が得ているエラーは、固定変数のものです。そのための可能な修正は何ですか?私が使用した次の関数の a のような厳格な変数を持つ配列を作成する方法のアイデアを教えてください

4

2 に答える 2

4

J. Abrahamson は、手元にあるエラーを修正する方法を説明しましたが、これは非常に複雑であることに注意してください。すべてのローカル型シグネチャを省略できます1。コンパイラはそれらを単独で推論できます。(確かに、ローカル型シグネチャが必要なアプリケーションや、読みやすさに役立つアプリケーションは十分ScopedTypeVariablesあります。多くの場合、 が必要になります。しかし、IMO のような単純な関数には必要ありません。)

不必要な複雑さについて言えば、 で作成したばかりの配列を明示的にインデックス反復処理することには何のメリットもありませんlistArray。これは、リストを再帰的に破壊することとほとんど同じです (ただし、はるかに扱いにくくなります)。そして、それは折り畳みとして書くことができます。または、このような場合、2 つのリストを「並行して」反復処理しzip、それらのリストを折りたたみます。実際には、折り畳みさえ必要ありません。通常、複数の要素をバッチで更新する必要があるため、単一のペアではなく、インデックスと値のペアのリストを受け入れる正当な理由あり(//)ます。

これにより、関数が大幅に簡素化されます。

rearrange l la = elems $ posarr // zip l la
  where posarr = listArray (1, length l) la

1したがって、誤解されていません。つまり、ローカル型シグネチャのみを意味します。トップレベルでは、モジュール内でのみ使用されるおそらく完全に些細なものを除いて、すべてに署名が必要です(ただし、ある意味ではローカル署名でもあります)。

2これには単なる便利さ以上のものがあります: あなたのソリューションは実際には非常に非効率的です. なぜなら, 各変更ステップで配列全体のコピーを作成する必要があるため, 純粋関数型言語で中間結果に安全にアクセスできるからです. //複数のペアをすぐに呼び出すと、これが省略されます: 中間ステップが公開されることはないため、GHC は内部で魔法を実行でき、命令型言語 (またはモナドを使用する Haskell)でできるように破壊的な更新を実行できます。STこれははるかに高速です。

于 2013-11-09T17:29:23.370 に答える