TL展開;博士:是否有可能使用任何lens
家族的抽象的包裝/解開任意newtype
(即提供了一種用於這樣的抽象的實例)?如何消除包裝的樣板和使用鏡片
我會通過一個基於真實故事的簡單示例來激發我的問題。假設我定義以下newtype
:
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
兩個例子游離單糖是產物序列和序列:
type FreeSum a = FreeMonoid (Sum a)
type FreeProduct a = FreeMonoid (Product a)
其中Sum
和Product
在Data.Monoid
中定義。現在,我們可以定義fromList
和toList
操作爲FreeSum
和 FreeProduct
如下:
fromListSum :: Ord a => [a] -> FreeSum a
fromListSum = fromList . (Sum <$>)
fromListProduct :: Ord a => [a] -> FreeProduct a
fromListProduct = fromList . (Product <$>)
但是,這裏有相當多的樣板。這將會是更好,如果我們可以簡單地說:
fromListW :: (Ord a, Wrapper f) => [a] -> FreeMonoid (f a)
fromListW = fromList . (wrap <$>)
其中wrap
是(hypotetical)的一些操作Wrapper
類分別爲:
wrap :: a -> f a
unwrap :: f a -> a
同樣,我希望能夠寫的函數:
toListW :: (Ord a, Wrapper f) => FreeMonoid (f a) -> [a]
toListW = (unwrap <$>) . toList
鏡頭似乎在Control.Lens.Wrapped
提供這樣的抽象(對於該Sum
和Product
在這個例子中是斯塔那裏的特殊類的東西!)。然而,我在這個模塊中理解和使用抽象的嘗試失敗了。例如:
fromListW :: (Ord a, Wrapped (f a)) => [a] -> FreeMonoid (f a)
fromListW = fromList . (Wrapped <$>)
將不起作用,因爲參數不是Unwrapped (f a)
的列表。
所以我的問題是:
- 待辦事項鏡頭提供與此類似
Wrapper
類的抽象? - 如果不是,可以通過使用鏡頭解決這個「scrap-your-boilerplate」問題嗎?
感謝偉大的答案。目前還不清楚該解決方案的工作原理和原因,但我希望在我深入研究鏡頭之後能夠了解這一點。在此期間[這裏](https://github.com/capitanbatata/sandbox/blob/master/pw-lenses/src/corercions.lhs)是一些工作代碼。 –