如何消除使用镜头包装和展开的样板

时间:2017-09-26 11:41:10

标签: haskell lens lenses newtype

tl; dr :是否可以使用任何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)

Data.Monoid中定义SumProduct的位置。现在,我们可以为fromListtoList定义FreeSumFreeProduct次操作 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

其中Wrapper是(hypotetical)wrap :: a -> f a unwrap :: f a -> a 类的一些操作:

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

同样,我希望能够编写一个函数:

Sum

镜头似乎在Control.Lens.Wrapped中提供了这样的抽象(在这个例子中ProductfromListW :: (Ord a, Wrapped (f a)) => [a] -> FreeMonoid (f a) fromListW = fromList . (Wrapped <$>) 是那里的类型类的实例!)。但是,我尝试理解和使用此模块中的抽象失败了。例如:

Unwrapped (f a)
由于参数不是Wrapper的列表,

无法工作。

所以我的问题是:

  • 镜头是否提供类似于此FILE_APPEND类的抽象?
  • 如果没有,这可以&#34;废弃你的样板&#34;问题可以通过使用镜头解决吗?

1 个答案:

答案 0 :(得分: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实现具有类似的结构:

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