如何为这种数据类型编写Semigroup实例?

时间:2016-09-12 18:40:09

标签: haskell

我试图在Haskell Book(第15章," Monoid,Semigroup")中进行Semigroup练习之一但是我被卡住了。以下是:

newtype Combine a b =
  Combine { unCombine :: (a -> b) }

我应该为Semigroup编写Combine个实例。

然后书说它必须表现如下:

 Prelude> let f = Combine $ \n -> Sum (n + 1)
 Prelude> let g = Combine $ \n -> Sum (n - 1)
 Prelude> unCombine (f <> g) $ 0
 Sum {getSum = 0}
 Prelude> unCombine (f <> g) $ 1
 Sum {getSum = 2}
 Prelude> unCombine (f <> f) $ 1
 Sum {getSum = 4}
 Prelude> unCombine (g <> f) $ 1
 Sum {getSum = 2}

所以我首先开始使用错误的解决方案进行类型检查:

instance Semigroup (Combine a b) where
  Combine f <> Combine g = Combine f

这当然不是预期的,但希望朝着正确的方向迈出一步。我的想法类似于以下内容,在伪代码中:

 instance Semigroup (Combine a b) where
   (Combine f) <> (Combine g) = Combine (SOMETHING)

SOMETHING fg附加,无论具体的追加操作是什么(取决于fg);所以我认为这需要来自<>的{​​{1}},但我的代码中已经有Data.Monoid,因此来自import Data.Semigroup的{​​{1}}与<>中的Data.Monoid重合1}}。那我该怎么办?

我试图找出如何陈述类似&#34;组合(f Monoid&#39; s&gt; g)&#34;但是无法找到答案。

本书还说明,除非我使用GHC 8.x,否则我必须导入Data.Semigroup并且我可能会使用&#34; shadow&#34;来自Semigroup的{​​{1}};但是我很难找到如何产生这种效果。

有什么想法吗?

2 个答案:

答案 0 :(得分:10)

他们想要的可能是添加功能。为此,类型b需要是半群:

import Data.Semigroup

newtype Combine a b =
  Combine { unCombine :: (a -> b) }

instance Semigroup b => Semigroup (Combine a b) where
  (Combine f) <> (Combine g) = Combine (\x -> f x <> g x)

答案 1 :(得分:4)

您可以通过这种方式隐藏Monoid的{​​{1}}:

(<>)

然后当你import Data.Monoid hiding ((<>)) 时,你的范围只有一个import Data.Semigroup:来自(<>)的那个。