Haskell 我怎样才能使(折叠s a)从控制镜头变成幺半群?

Haskell 我怎样才能使(折叠s a)从控制镜头变成幺半群?,haskell,haskell-lens,Haskell,Haskell Lens,我拿着镜片和棱镜瞎混,我有点陷入了困境。我想在模板Haskell中编写以下内容,但它无法编译: data Suit = Spade | Heart | Diamond | Club makePrisms ''Suit blackSuits = _Spade <> _Club 通过用(>)替换p,我可以将该类型放宽到 (Applicative f, Monoid (f Suit)) => (() -> f ()) -> Suit -> f Suit 它与折叠

我拿着镜片和棱镜瞎混,我有点陷入了困境。我想在模板Haskell中编写以下内容,但它无法编译:

data Suit = Spade | Heart | Diamond | Club
makePrisms ''Suit
blackSuits = _Spade <> _Club
通过用
(>)
替换
p
,我可以将该类型放宽到

(Applicative f, Monoid (f Suit)) => (() -> f ()) -> Suit -> f Suit
它与折叠套装()的唯一区别在于后者具有
(应用型f,逆变型f)=>…
而不是
幺半群(f套装)
限制。当我读到
逆变
时,我看到断言
(应用f,逆变f)
一起意味着
f
实际上是某些幺半群
r
常数r
。这似乎表明上述类型实际上是
折叠套装()的子集。但是当我尝试向代码中添加
blackSuits::Fold Suit()
时,我得到了

Could not deduce (Monoid (f Suit)) arising from a use of ‘<>’
from the context (Contravariant f, Applicative f) ...
无法推断因使用“”而产生的(幺半群(f诉讼))
从上下文(逆变f、应用f)。。。

如果我只是尝试在折叠上定义幺半群而不是从棱柱开始,我会得到类似的错误。我没有尝试过让
Fold s a
a
Monoid
通过编译器。有什么办法可以使这一点起作用吗?

如果您查看
折叠签名:

type Fold s a = forall f. (Contravariant f, Applicative f)=> (a -> f a) -> s -> f s
它说它必须为所有的
反变的
应用的
工作。使用
将两个折叠组合在一起时,函数
实例半群b=>半群(a->b)
半群
要求
fs
半群
。这意味着它将不再以
折叠方式键入check。但是,大多数(所有?)在
镜头中折叠的函数仍然会接受这一点,因为它们使用
获取rsa=(a->Const r a)->s->Const r s
,这将进行类型检查

你可以做几件事。您可以使用具有自己的
Monoid
实例的newtype:

> :set -XTemplateHaskell
> import Control.Lens
> import Data.Semigroup
> data Suit = Spade | Heart | Diamond | Club; makePrisms ''Suit
> let blackSuitsFold = runFold $ Fold _Spade <> Fold _Club :: Fold Suit ()
啊,这就是“物化”褶皱的作用!谢谢
> :set -XTemplateHaskell
> import Control.Lens
> import Data.Semigroup
> data Suit = Spade | Heart | Diamond | Club; makePrisms ''Suit
> let blackSuitsFold = runFold $ Fold _Spade <> Fold _Club :: Fold Suit ()
> let cloneFold = foldring . foldrOf
> let blackSuitsClone = cloneFold $ _Spade <> _Club :: Fold Suit ()
> let blackSuitsGetter = _Spade `mappend` _Club :: Monoid r => Getting r Suit ()
> has blackSuitsGetter Spade
True