如何从Control.Lens中制作(折叠a)一个幺半群?

时间:2016-07-12 22:54:01

标签: haskell lens

我在镜头和棱镜上鬼混,我已经进入了杂草。我想在模板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对于某些幺半群Const r实际上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通过编译器。有没有办法让这项工作?

1 个答案:

答案 0 :(得分:4)

如果你看一下Fold签名:

type Fold s a = forall f. (Contravariant f, Applicative f)=> (a -> f a) -> s -> f s

它说它必须适用于fContravariant所有 Applicative。当您使用<>将两个折叠组合在一起时,函数Semigroup的{​​{1}}实例要求instance Semigroup b => Semigroup (a -> b)f s。这意味着它将不再将检查类型设为Semigroup。但是,大多数(所有?)在Fold中进行折叠的函数仍然会接受这个函数,因为它们会使用lens,这会键入check。

你可以做几件事。您可以使用Fold newtype,它具有自己的Getting r s a = (a -> Const r a) -> s -> Const r s实例:

Monoid

或者你可以&#34;克隆&#34;折叠:

> :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 () ,您可以使用Fold同义词,这在大多数情况下都会起作用:

Getting