7

lens特定の問題のためにライブラリを使用するのに苦労しています。渡ろうとしている

  1. 更新されたデータ構造
  2. その更新された構造の一部に焦点を合わせたレンズ

別の関数に、g. gデータ構造からの共有情報と一部の情報が必要なため、レンズとデータ構造の両方を渡します。(それが役立つ場合、データ構造には結合確率分布に関する情報が含まれていますが、gいずれかの限界でのみ機能し、私が見ている限界を知る必要があります。2 つの限界の唯一の違いは、定義の残りの部分との平均です。データ構造で共有されています)。

私の最初の試みはこのように見えました

f :: Functor f => Params -> ((Double -> f Double) -> Params -> f Params) -> a
f p l = g (l %~ upd $ p) l
  where upd = ...

g p x = go p p^.x

しかし、更新用およびゲッター用であるfと推測されるため、コンパイル中に失敗します。IdentityConst Double

私がやりたいことを達成するための最良の方法は何ですか? 次のいずれかを実行できると想像できます。

  1. レンズのコピーを作成して、タイプの推論がケースごとに異なるようにする
  2. 更新された構造とレンズを渡すのではなく、元の構造と変更された値を返すレンズを渡します (レンズが参照する構造の部分のみを更新する場合)。
  3. 関数/データ構造のより良い設計選択を行う
  4. まったく違うもの

助けてくれてありがとう!

4

3 に答える 3

10

András Kovács の回答は、 でこれを達成する方法を示していますRankNTypes。を避けたい場合は、 andRankNTypesを使用できます。ALenscloneLens

f :: a -> ALens' a Int -> (Int, a)
f a l = (newvalue, a & cloneLens l .~ newvalue)
  where oldvalue = a^.cloneLens l
        newvalue = if oldvalue == 0 then 0 else oldvalue - 1

Control.Lens.LoupeALensは、の代わりに機能する演算子と関数を提供しますLens

<<%~多くの場合、同様である%~が古い値<%~を返す 、または新しい値を返すも使用できるはずです。

f :: a -> LensLike' ((,) Int) a Int -> (Int, a)
f a l = a & l <%~ g
  where g oldvalue = if oldvalue == 0 then 0 else oldvalue - 1

これには、 (ターゲット タイプが a の場合) と一緒に、Isosまたは場合によっては一緒に機能するという利点があります。TraversalsMonoid

于 2014-05-02T13:18:47.170 に答える
2

ベンノは一般的な目的で最も優れた回答をしました。

他にも 2 つのオプションがありますが、完全を期すためにここで紹介します。

1.)

にはいくつかのLoupeコンビネータがありLensます。

http://hackage.haskell.org/package/lens-4.1.2/docs/Control-Lens-Loupe.html

それらはすべて、 を含む名前を持っています#

^##%=どちらも特定ALensの具体的なファンクターの選択でインスタンス化されたレンズです。

これは、レンズのリストを渡す必要がある場合、または本当に複数のパスが必要な場合に役立ちます。

2.)

別の選択肢であり、私の好みの戦術は、両方の操作を同時に行う方法を見つけることです。

ここで変更していますが、設定した値が必要です。はい、<%~代わりに を使用することでそれが得られます%~

これで、ファンクターを 1 つ選択してレンズをインスタンス化するだけで、コードが高速化されます。

于 2014-05-02T17:45:53.003 に答える