ファーストクラスの値にバンドルされたゲッターとセッターは、レンズと呼ばれます。これを行うためのパッケージはかなりあります。最も人気のあるのはデータレンズとfclabelsです。この前のSOの質問は良い入門書です。
これらのライブラリは両方とも、Template Haskellを使用したレコード定義からのレンズの導出をサポートしています(データレンズを使用すると、移植性のための追加パッケージとして提供されます)。あなたの例は次のように表現されます(data-lens構文を使用):
setL idxF_s (b ^. idL_s) a
(または同等にidxF_s ^= (b ^. idL_s) $ a
:)
もちろん、ゲッターとセッターを一緒に変換することで、一般的な方法でレンズを変換できます。
-- I don't know what swap_by_sign is supposed to do.
negateLens :: (Num b) => Lens a b -> Lens a b
negateLens l = lens get set
where
get = negate . getL l
set = setL l . negate
(または同等に:negateLens l = iso negate negate . l
1)
一般的に、重要なレコード処理を処理する必要がある場合は、レンズを使用することをお勧めします。レコードの純粋な変換を大幅に簡素化するだけでなく、両方のパッケージに、レンズを使用して状態モナドの状態にアクセスして変更するための便利な関数が含まれています。これは非常に便利です。(data-lensの場合、data-lens-fdパッケージを使用して、これらの便利な関数を任意の場所で使用することをお勧めしますMonadState
。繰り返しになりますが、移植性のために別のパッケージに含まれています。)
1いずれかのパッケージを使用する場合は、モジュールを次のコマンドで開始する必要があります。
import Prelude hiding (id, (.))
import Control.Category
これは、プレリュードid
と(.)
関数の一般化された形式を使用しているためid
です。任意の値からそれ自体までレンズとして使用でき(確かに、それほど有用ではありません)、(.)
レンズを構成するために使用されます(たとえばgetL (fieldA . fieldB) a
、と同じgetL fieldA . getL fieldB $ a
です)。短いnegateLens
定義ではこれを使用します。