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)是一些工作代码。 –