7

要素のリストを含むネストされたデータ構造の操作を実行しようとしています。さまざまなアプローチをいじくり回した後、最終的にこれを行うための最良の方法としてレンズに落ち着きました。それらは、構造の特定の要素を見つけて変更するのに完全に機能しますが、これまでのところ、新しい要素を追加する方法に困惑しています。

私が読んだことから、トラバーサルの法則に違反して新しい要素をリストに挿入するため、トラバーサルを技術的に使用することはできません。これは、最初にトラバーサルを使用してそれを行う方法さえ理解できると仮定しています(私はまだ Haskell にかなり弱く、lens パッケージ内のほとんどのものの型シグネチャには頭が回転します)。

具体的に私が達成しようとしているのは、特定のセレクターに一致する要素のリストでいくつかの要素を見つけ、一致した要素の前または後に新しい要素を挿入することです(前または後の関数への異なる引数)マッチ)。Control.Lens には、私がやろうとしていることを達成できる何かが既にありますか? 型シグネチャについての私の理解は弱すぎてそれを見ることができませんか? 私がやろうとしていることを達成するためのより良い方法はありますか?

リストの最初または最後に新しい要素を追加しようとしているだけなら、かなり簡単ですが、途中の特定の場所に挿入するのは難しい部分です。私が書いたレンズ前のコードのいくつかでは、私が望んでいたことを達成するために折り目を使用しましたが、構造のより深くネストされた部分 (折り目の内側の折り目の内側の折り目など) で危険になり始めていたので、私は Control.Lens に目を向けて、その混乱の一部を解き明かそうとしました。

4

3 に答える 3

7

レンズパッケージの使用

関数idをレンズのように使用できることを知ることから始めると、次のようになります。

import Control.Lens
> [1,2,3,4] ^. id
[1,2,3,4]

次に、リストを変更する方法に移ります。

> [1,2,3,4] & id %~ (99:)
[99,1,2,3,4]

上記により、リストの先頭に挿入できます。リストの後半部分に注目するために、 Control.Lens.Cons モジュール_tailから使用できます。

> [1,2,3,4] ^. _tail
[2,3,4]
> [1,2,3,4] & _tail %~ (99:)
[1,99,2,3,4]

これを n 番目の位置に一般化します。

> :{
let
_drop 0 = id
_drop n = _tail . _drop (n - 1)
:}
> [1,2,3,4] ^. _drop 1
[2,3,4]
> [1,2,3,4] & _drop 0 %~ (99:)
[99,1,2,3,4]
> [1,2,3,4] & _drop 1 %~ (99:)
[1,99,2,3,4]

orを使用できるConsインスタンスを使用して、これをすべての型に一般化する最後のステップです。cons<|

> [1,2,3,4] & _drop 1 %~ (99<|)
[1,99,2,3,4]
> import Data.Text
> :set -XOverloadedStrings
> ("h there"::Text) & _drop 1 %~ ('i'<|)
"hi there"
于 2015-10-23T05:40:31.333 に答える
2

あなたの問題に関するいくつかのコメント:

質問に答える: あなたのやりたいことを実現する方法があるかもしれません。Lens ライブラリは驚くほど汎用的です。そこにないものは、それを実現するための単純または明白な方法です。partsOfコンビネータが関係すると思いますが、よくわかりません。

レンズに関するコメント: レンズ ライブラリは非常に優れており、驚くほど多くの問題に適用できます。ライブラリを学習しているときに最初に思ったのは、すべてを Lens アクセスまたはミューテーションに適合させようとすることでした。私が発見したのは、レンズ ライブラリを使用して複雑なデータ構造を掘り下げる方が良いということでしたが、単純な要素ができたら、Lens ライブラリを使いすぎて拡張するよりも、既に知っている従来の関数型手法を使用する方が良いということでした。限界。

あなたが求めていないアドバイス: リストの途中に要素を挿入するのは悪い考えです。実行できないわけではありませんが、最終的に O(n^2) 操作になる可能性があります。(このStackOverflowの回答も参照してください。)Zipリストまたはその他の機能データ構造の方が良い考えかもしれません。副次的な利点として、これらの構造の一部をAtクラスのインスタンスにすることで、部分レンズ コンビネータを使用して挿入と削除を行うことができます。

于 2013-08-28T07:37:04.433 に答える