2013-06-07 9 views
15

私はフィールドのたくさんのデータ型を持っている:関数を代数データ型のフィールドにマップするより簡潔な方法はありますか?

data ManyFields a b c d .. = MF { f1 :: a, f2 :: b, f3 :: c .. } 

問題の一つ

それぞれに対してmap機能を実現回避しながら、どのようにして、各フィールドに機能をマッピングします。 は、例えば、これは非常に退屈で非慣用的になります。

-- | Note I am explicitly constructing ManyField after mapping a function onto the field 
-- | This looks bad 
mapf1 :: (a -> a1) -> ManyFields a b c .. -> ManyFields a1 b c .. 
mapf1 g mf = MF (g . f1 $ mf) (f2 mf) .. 

-- | Repeat for each field 
mapf2 :: (b -> b1) -> ManyFields a b c .. -> ManyFields a b1 c ... 

を私はconstructor . (mapfunction f)のパターンうち抽象は、定型を削減することを高次機能のいくつかの並べ替えを考えて、より良い解決策はありますか?私は一緒に多くのManyFieldsを圧縮し、各フィールドに任意のアリティの機能をマップする場合、それはいくつかの型クラスのインスタンスである可能性のような二

問題は、このサウンドしていますか?

ユースケース:

(==) `mapFunction` mf1 `pairWiseZipField` mf2 

それは一種の私には応用的のように見えますが、やはり私はこのタイプにfmapを実装するかどうかはわかりません。

答えて

19

これは実際には標準機能では実行できません。最良の方法は、各フィールドにマップ機能を持たせることです。幸いにも、あなたはlensライブラリのテンプレートhaskellを使ってこれらを自動的に生成することができます。

data ManyFields a b c d = MF { _f1 :: a, _f2 :: b, _f3 :: c, _f4 :: d } 

makeLenses ''ManyFields 

これはManyFieldsの各フィールドのレンズを生成します。それは次のようになります。レンズは簡単な構造で、の値を変更することができます - 変更はマップと同じように多形にすることもできます!各フィールドの先頭にアンダースコアが付いていることに注意してください。レンズの名前はフィールドの下線を引いたものと同じです。

あなたは今、このような値にアクセスすることができます

> foo = MF 'a' "b" 3 False 
> foo^.f1 
'a' 

あなたはset演算子を使用して値を設定することができます。

> :t set f1 
set f1 :: a' -> ManyFields a b c d -> ManyFields a' b c d 

実際にそれを使用するには、あなたがこれを行うことができます:あなたはゲッターとセッター、書き込みを持っているので

> set f1() foo 
MF() "b" 3 False 

は、マップ機能があるレンズを使用した場合、それは、setter関数を作成しますかなり些細なことだ。幸いなことに、私たちもこれを行う必要はありません:あなたは中置演算子のように多くの、set.~呼び出すことができ、オーバー%~呼び出すことができる場合

> :t over f1 
over f1 :: (a -> a') -> ManyFields a b c d -> ManyFields a' b c d 

:ライブラリがoverと呼ばれる機能を提供します。 (後者はニーモニックを持っています:%はmod、または "modify"です:P。)これは演算子($を反転したもの)でも役に立ちます。したがって、次の2つのバージョンは同じです:

> over f1 ord foo 
MF 97 "b" 3 False 
> foo & f1 %~ ord 
MF 97 "b" 3 False 

私は個人的には演算子が少しだと思います。レンズどこでもを使用しない限り、私はsetoverに固執します。

説明したように機能を圧縮するための良い解決策はありません。しかし、レンズライブラリーの残りの部分を見てください - それはかなり大きいです、そして、あなたはあなたが何を見つけるのかを決して知らない!

+5

私はこれがレンズの優れた紹介だと思っています。私はこの問題に対する最良の解決策だと思います。 – AndrewC

関連する問題