2016-07-01 3 views
4

ほとんどの場合、レコードを作成するたびに、すぐにmakeLenses ''Recordlens)を追加しています。実際にレコードが与える投影関数を使用することはありません。実際には、makeLensesが(GHC -ddump-splicesフラグ付きで)何を生成しているかを見ると、生成するレンズの名前を選択する以外は、それらの投影関数を使用していないように見えます。レコード投影関数をレンズに置き換えます。

TemplateHaskell、またはプリプロセッサ、または他の魔法のような方法がありますが、レコード投影機能を使ってVan Laarhovenレンズをまっすぐにすることはできますか?

data Record a b = Record { x :: a, y :: b } 

する(type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f tで)生成するであろうことを意味すること、明確にすること

x :: forall a b c. Lens (Record a b) (Record c b) a c 
x f (Record _x _y) = fmap (\x' -> Record x' _y) (f _x) 

y :: forall a b c. Lens (Record a b) (Record a c) b c 
y f (Record _x _y) = fmap (\ y' -> Record _x y') (f _y) 

代わりの

x :: forall a b. Record a b -> a 
x (Record _x _y) = _x 

y :: forall a b. Record a b -> b 
y (Record _x _y) = _y 

それは定型を取り除くでしょうだけでなく、 makeLensesでも名前空間を解放することができます(投影func決して定義されません)。

GHCがあり...

+1

https:// hackage.haskell.org/package/record? –

答えて

5

これは軽微なものであるが、それはすべての私の記録に取り付けられており、レコードは、そのような珍しいものではありませんだから、それは本当に私の神経に取得し始めています拡張提案はOverloadedRecordFields/MagicClassesと呼ばれます。 Adam Gundry is working on an active pull request。これは、OverloadedRecordLabelsと組み合わせて、この非常に問題に対処することを意図しています! Fooのような例のデータ型と

data Foo = Foo { x :: Int, y :: Int } 

class IsLabel (x :: Symbol) a where 
    fromLabel :: Proxy# x -> a 

、表現#x (foo :: Foo)で部分式#xは魔法fromLabel @"x" @Foo proxy#にコンパイラによって展開されます。その@記号、型適用記号は、別のGHC 8-ismです。

xと異なり、#xの動作は、必要に応じて変更できます。通常の投影機能に過ぎないかもしれません。あなたはすぐにできたような例では

​​

instance HasField name big small => IsLabel name (big -> small) where 
    fromLabel proxy big = getField proxy big 

それともたちは刺しスタイルのレンズとの制約を満たすことができます:OverloadedLabelsを有効にすると、我々はすでに多型投影機能getFieldへのアクセス権を持っていますレンズとして#xを使用して開始:

over #x (* 2) (Foo 1008 0) -- evaluates to Foo 2016 0 
+0

ああ...私はこのようなことをどうやって望んでいたのかは、作品にありました。なんて可愛らしいです!どうもありがとうございました。受け入れる前に1日ほど待つかどうか。 – Alec

+1

この提案にどれくらいの距離があるか考えてみましょうか? – SwiftsNamesake

関連する問題