2017-09-26 16 views
0

TLを使用して、DRを:それは/いずれかの任意newtype(すなわち、このような抽象化のインスタンスを提供する)アンラップラップする抽象化のlensファミリーのいずれかを使用することが可能ですか?どのように包装の定型を排除し、アンラッピングレンズ

私は真実の物語に基づいて簡単な例で私の質問を動機づけます。

フォームの条件を表すために使用される
newtype FreeMonoid a = FreeMonoid { asMap :: Map a Int } 

a0 <> a1 <> ... <> an-1 

我々はリストとして自由モノイドを表すことができますの

instance Ord a => IsList (FreeMonoid a) where 
    type Item (FreeMonoid a) = a 
    fromList xs = FreeMonoid $ Map.fromListWith (+) $ zip xs (repeat 1) 
    toList (FreeMonoid p) = do 
     (x, n) <- Map.toList p 
     genericReplicate n x 

2つの例を、私は、次のnewtypeを定義すると仮定遊離モノオールは、和および生成物の配列のシーケンスである:

type FreeSum a = FreeMonoid (Sum a) 
type FreeProduct a = FreeMonoid (Product a) 

SumおよびProductは、Data.Monoidで定義されています。

fromListSum :: Ord a => [a] -> FreeSum a 
fromListSum = fromList . (Sum <$>) 

fromListProduct :: Ord a => [a] -> FreeProduct a 
fromListProduct = fromList . (Product <$>) 

をしかし、これは定型のかなり多くを持っている:今、次のように、私たちはFreeSumFreeProductためfromListtoList操作を定義することができます。 wrapは(hypotetical)のいくつかの操作が

fromListW :: (Ord a, Wrapper f) => [a] -> FreeMonoid (f a) 
fromListW = fromList . (wrap <$>) 

ですWrapperクラスは以下の通りであった::

wrap :: a -> f a 
unwrap :: f a -> a 

同様に、私は書くことができるようにしたいのですが、我々は単純に言うことができればよりよいだろう関数:

toListW :: (Ord a, Wrapper f) => FreeMonoid (f a) -> [a] 
toListW = (unwrap <$>) . toList 

レンズはControl.Lens.Wrappedこのような抽象化を提供するように思われる(この例ではSumProductがINSTAであるためそこにはタイプメスのネズミ!)。しかし、このモジュールの抽象概念を理解して使用しようとする私の試みは失敗しました。例:

fromListW :: (Ord a, Wrapped (f a)) => [a] -> FreeMonoid (f a) 
fromListW = fromList . (Wrapped <$>) 

のリストではないため、このフィールドは機能しません。

だから私の質問は次のとおりです。

  • ドゥレンズは、このWrapperクラスに似た抽象化を提供?
  • もしそうでなければ、レンズを使ってこの問題を解決できますか?

答えて

1

"問題"はWrappedを使用していることです。これは実際には便利なパターンの同義語であり、折り返し "コンストラクタ"ではありません。多型折り返しをサポートするために設計されていますので、あなたはあなたのタイプをリラップすることができることを主張する必要があります。

fromListW :: (Rewrapped a a, Ord a) => [Unwrapped a] -> FreeMonoid a 
fromListW = fromList . (Wrapped <$>) 

を、この後、期待通りに動作します:

> let x = [1,2,3] 
> fromListW x :: FreeMonoid (Sum Int) 
FreeMonoid {asMap = fromList [(Sum {getSum = 1},... 
> fromListW x :: FreeMonoid (Product Int) 
FreeMonoid {asMap = fromList [(Product {getProduct = 1},... 
> 

は、私はより多くの慣用的なレンズの実装が可能だと思う:

fromListW :: (Rewrapped a a, Ord a) => [Unwrapped a] -> FreeMonoid a 
fromListW = fromList . view (mapping _Unwrapped) 

これはまだRewrapped a a制約を必要としますが、代わりに、非多型_Unwrapped'を使用することができます。

fromListW :: (Wrapped a, Ord a) => [Unwrapped a] -> FreeMonoid a 
fromListW = fromList . view (mapping _Unwrapped') 

もう少し自然に見えます。偉大な答えを

toListW :: (Wrapped a, Ord a) => FreeMonoid a -> [Unwrapped a] 
toListW = view (mapping _Wrapped') . toList 
+0

ありがとう:

toListW実装では、同様の構造を持っているでしょう。どのように、なぜソリューションが機能するのかはまだ不明ですが、私はレンズに深く浸ってから理解が来ることを願っています。それまでのところ、[ここ](https://github.com/capitanbatata/sandbox/blob/master/pw-lenses/src/Coercions.lhs)は実用的なコードです。 –

関連する問題