2016-10-27 12 views
1

レンズからmakeFieldsを使用して、さまざまな構造にオーバーロードされたフィールドを生成しています。これらのフィールドを、複数の構造を持つフィールドで使用したいと考えていますが、どのフィールドを1回だけ使用したいのかを述べる必要があります。makeFieldsの任意の引数を同じ関数内の異なる型で使用する方法は?

{-# LANGUAGE RankNTypes #-} 
{-# LANGUAGE TemplateHaskell #-} 
{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE FunctionalDependencies #-} 
{-# LANGUAGE FlexibleInstances #-} 

import Control.Lens 

data A = A 
    { _aX :: String 
    , _aY :: String 
    } 
makeFields ''A 

data B = B 
    { _bX :: String -> Char 
    , _bY :: String -> Bool 
    } 
makeFields ''B 

-- x can get _aX from an A and _bX from a B 

a :: A 
a = undefined 

b :: B 
b = undefined 


q :: (Getter A String) AND (Getter B (String -> a)) -> a 
q lens = (b^.lens) (a^.lens) 

どのようなタイプを指定すればよいですかq?私はGHCに型を推測させようとしましたが、失敗しました。

GHCi> :t x 
x :: (HasX s a, Functor f) => (a -> f a) -> s -> f s 

すべてのx -bearingのタイプをカバーするので、抽象化(抽象化I:どう処理するかを決定する

+0

'(b^.lens)a^.lens' ='((b^.lens)a)^。あなたはおそらく '(b^.lens)(a^.lens)'を望むでしょう。しかし、 '(Getter X Y、...)'型は有効ではないので(impadicative)、 'ReifiedGetter'やライター' Getter A ..-> Getter B ..-> .. 'を使う必要があります。 – user2407038

+0

@ 2426021684なぜ2つの「ゲッター」が_same_レンズである必要がありますか? –

+0

@BenjaminHodgson同じレンズを関数に2回渡す必要はありません。 – 2426021684

答えて

1

、我々はあなた(makeField -generated)フィールドの種類が何であるかを知っておく必要がありますあなたがmakeFieldsを使用していたことに気付く前に泣いていました)は、マルチパラメータタイプのクラスHasXであり、他のフィールドでも同様です。それは、私たちは十分に単一の実装にはさまざまな種類のxを使用することができます:

-- Additional extension required: FlexibleContexts 
-- Note that GHC is able to infer this type. 
qx :: (HasX t (a -> b), HasX s a) => t -> s -> b 
qx t s = (t ^. x) (s ^. x) 
GHCi> import Data.Maybe 
GHCi> let testA = A "foo" "bar" 
GHCi> let testB = B (fromMaybe 'ø' . listToMaybe) null 
GHCi> qx testB testA 
'f' 

、しかし、あなたが求めてかなりのものではないこと。しかし、実際には、そうです。ここCould we abstract over type classes?に示されているようにConstraintKinds延長にやや実現可能なおかげで、行うなど、クラスHasXHasYを超える抽象化する必要があり、ことを達成

q xOrY b a = (b^.xOrY) (a^.xOrY) 

:あなたはのようなものを望んでいましたそれは行く:

-- Additional extensions required: ConstraintKinds, ScopedTypeVariables 
-- Additional import required: Data.Proxy 
-- GHC cannot infer this type. 
q :: forall h s t a b. (h t (a -> b), h s a) => Proxy a -> Proxy h 
    -> (forall u c. h u c => Getting c u c) -> t -> s -> b 
q _ _ l t s = 
    (t ^. (l :: Getting (a -> b) t (a -> b))) (s ^. (l :: Getting a s a)) 
GHCi> q (Proxy :: Proxy String) (Proxy :: Proxy HasX) x testB testA 
'f' 

間を決定する第1のプロキシ、あなたが一般性のこのビットをあきらめてaStringに置き換えない限り、仲介タイプは必要です。さらに、引数としてゲッターを渡し、第2のプロキシを介してフィールドを2回指定する必要があります。私は、この第2の解決策が問題の価値があると確信していません。qxqyなどを定義しなければならない余分な定型文は、ここに関わるすべての幸福よりかなり苦痛が少ないようです。それでも、読んでいる人の誰かが改善を提案したいと思うなら、私はすべて耳にします。

関連する問題