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
中定义Sum
和Product
的位置。现在,我们可以为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
其中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
中提供了这样的抽象(在这个例子中Product
和fromListW :: (Ord a, Wrapped (f a)) => [a] -> FreeMonoid (f a)
fromListW = fromList . (Wrapped <$>)
是那里的类型类的实例!)。但是,我尝试理解和使用此模块中的抽象失败了。例如:
Unwrapped (f a)
由于参数不是Wrapper
的列表,无法工作。
所以我的问题是:
FILE_APPEND
类的抽象?答案 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