我如何从 Control.Lens 制作 (Fold s a) 一个幺半群?
How can I make (Fold s a) from Control.Lens a monoid?
我在玩弄透镜和棱镜,我已经有点杂草了。我想在模板 Haskell 中编写以下内容,但它无法编译:
data Suit = Spade | Heart | Diamond | Club
makePrisms ''Suit
blackSuits = _Spade <> _Club
我对透镜和棱镜的了解(以及 Getter
文档中的评论)表明 _Spade <> _Club
应该是有效的 Fold Suit ()
。但是ghc无法编译上面的代码;它抱怨几个模棱两可的例子。 ghci 为 _Spade <> _Club
:
提供了以下类型签名
_Spade <> _Club
:: (Applicative f, Monoid (p Suit (f Suit)), Choice p) =>
p () (f ()) -> p Suit (f Suit)
并且通过将 p
替换为 (->)
我可以放宽该类型为
(Applicative f, Monoid (f Suit)) => (() -> f ()) -> Suit -> f Suit
它与 Fold Suit ()
的唯一区别是后者有 (Applicative f, Contravariant f) => ...
而不是 Monoid (f Suit)
限制。当我阅读 Contravariant
时,我看到断言 (Applicative f, Contravariant f)
一起暗示 f
对于某些幺半群 r
实际上是 Const r
。这似乎表明上面的类型实际上是 Fold Suit ()
的一个子集。但是当我尝试将 blackSuits :: Fold Suit ()
添加到我的代码时,我得到
Could not deduce (Monoid (f Suit)) arising from a use of ‘<>’
from the context (Contravariant f, Applicative f) ...
如果我只是尝试在折叠上定义幺半群而不是从棱镜开始,我会遇到类似的错误。我没有尝试让 Fold s a
成为 Monoid
通过编译器。有什么办法可以做到这一点吗?
如果您查看 Fold
签名:
type Fold s a = forall f. (Contravariant f, Applicative f)=> (a -> f a) -> s -> f s
它说它必须适用于 所有 f
,即 Contravariant
和 Applicative
。当您使用 <>
将两个折叠组合在一起时,函数 instance Semigroup b => Semigroup (a -> b)
的 Semigroup
实例要求 f s
为 Semigroup
。这意味着它将不再将检查类型作为 Fold
。但是,大多数(全部?)在 lens
中折叠的函数仍然会接受它,因为它们会在 Getting r s a = (a -> Const r a) -> s -> Const r s
中进行类型检查。
您可以做几件事。您可以使用 Fold
新类型,它有自己的 Monoid
实例:
> :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 ()
或者你可以"clone"弃牌:
> let cloneFold = foldring . foldrOf
> let blackSuitsClone = cloneFold $ _Spade <> _Club :: Fold Suit ()
或者,如果您不需要它成为 Fold
,您可以使用 Getting
同义词,这在大多数情况下都是一样的:
> let blackSuitsGetter = _Spade `mappend` _Club :: Monoid r => Getting r Suit ()
> has blackSuitsGetter Spade
True
我在玩弄透镜和棱镜,我已经有点杂草了。我想在模板 Haskell 中编写以下内容,但它无法编译:
data Suit = Spade | Heart | Diamond | Club
makePrisms ''Suit
blackSuits = _Spade <> _Club
我对透镜和棱镜的了解(以及 Getter
文档中的评论)表明 _Spade <> _Club
应该是有效的 Fold Suit ()
。但是ghc无法编译上面的代码;它抱怨几个模棱两可的例子。 ghci 为 _Spade <> _Club
:
_Spade <> _Club
:: (Applicative f, Monoid (p Suit (f Suit)), Choice p) =>
p () (f ()) -> p Suit (f Suit)
并且通过将 p
替换为 (->)
我可以放宽该类型为
(Applicative f, Monoid (f Suit)) => (() -> f ()) -> Suit -> f Suit
它与 Fold Suit ()
的唯一区别是后者有 (Applicative f, Contravariant f) => ...
而不是 Monoid (f Suit)
限制。当我阅读 Contravariant
时,我看到断言 (Applicative f, Contravariant f)
一起暗示 f
对于某些幺半群 r
实际上是 Const r
。这似乎表明上面的类型实际上是 Fold Suit ()
的一个子集。但是当我尝试将 blackSuits :: Fold Suit ()
添加到我的代码时,我得到
Could not deduce (Monoid (f Suit)) arising from a use of ‘<>’
from the context (Contravariant f, Applicative f) ...
如果我只是尝试在折叠上定义幺半群而不是从棱镜开始,我会遇到类似的错误。我没有尝试让 Fold s a
成为 Monoid
通过编译器。有什么办法可以做到这一点吗?
如果您查看 Fold
签名:
type Fold s a = forall f. (Contravariant f, Applicative f)=> (a -> f a) -> s -> f s
它说它必须适用于 所有 f
,即 Contravariant
和 Applicative
。当您使用 <>
将两个折叠组合在一起时,函数 instance Semigroup b => Semigroup (a -> b)
的 Semigroup
实例要求 f s
为 Semigroup
。这意味着它将不再将检查类型作为 Fold
。但是,大多数(全部?)在 lens
中折叠的函数仍然会接受它,因为它们会在 Getting r s a = (a -> Const r a) -> s -> Const r s
中进行类型检查。
您可以做几件事。您可以使用 Fold
新类型,它有自己的 Monoid
实例:
> :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 ()
或者你可以"clone"弃牌:
> let cloneFold = foldring . foldrOf
> let blackSuitsClone = cloneFold $ _Spade <> _Club :: Fold Suit ()
或者,如果您不需要它成为 Fold
,您可以使用 Getting
同义词,这在大多数情况下都是一样的:
> let blackSuitsGetter = _Spade `mappend` _Club :: Monoid r => Getting r Suit ()
> has blackSuitsGetter Spade
True