【问题标题】:mempty with different definition depending on whether mempty is left or right arg?mempty 的定义不同,具体取决于 mempty 是左参数还是右参数?
【发布时间】:2016-03-08 20:21:18
【问题描述】:

我有以下数据类型和半群实例:

data Or a b =
  Fst a
  | Snd b deriving (Eq, Show)

instance Semigroup (Or a b) where
  (<>) (Fst a) (Fst b) = Fst b
  (<>) (Snd a) (Fst b) = Snd a
  (<>) (Fst a) (Snd b) = Snd b
  (<>) (Snd a) (Snd b) = Snd a

我想为上述类型创建一个幺半群实例,但我不知道该怎么做。如果我使用以下定义

instance (Monoid a, Monoid b) => Monoid (Or a b) where
  mempty = (Fst mempty)
  mappend = (<>)

它将适用于 &lt;&gt; 的所有输入对,除了我 mappend 的输入对

(Fst a) <> mempty

这将评估为mempty

如何解决此问题以使mempty 有效?似乎没有一些新的语法或概念就无法完成,因为它取决于内存是在左边还是右边......

【问题讨论】:

  • 老实说,这里似乎没有一个幺半群。 没有标识元素。
  • 奇怪。为它实现一个幺半群是 Haskell 书中的一个练习,haskellbook.com

标签: haskell monoids semigroup


【解决方案1】:

有一个非常好的(更简单的)半群,它总是接受它的第一个参数:

newtype FirstS a = FirstS a
instance Semigroup (FirstS a) where
    a <> b = a

不幸的是,它不是一个幺半群,因为——除了包装类型的琐碎选择——这个操作没有左标识。标准的First 类型通过添加一个可区分的标识元素来修补FirstS,因此:

newtype First a = First (Maybe a)
instance Semigroup (First a) where
    First Nothing <> b = b
    a <> First Nothing = a
    a <> b = a -- this clause is exactly as before

然后很容易通过选择mempty = First Nothing 来编写Monoid 实例。您可以通过向您的类型添加一个可分辨的标识元素来实现类似的技巧:

data Or a b = Fst a | Snd b | Neither
instance Semigroup (Or a b) where
    Neither <> b = b
    a <> Neither = a
    -- the remainder of the clauses are as before

这使得mempty = Neither 的选择变得非常容易。

这种模式非常有用,它实际上在semigroups 中有一个新类型包装器,因此您也可以使用原来的Or a b 类型编写这个补丁类型,就像简单的Option (Or a b) 并得到Semigroup 和@ 987654334@ 个免费实例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-22
    • 1970-01-01
    • 2015-12-26
    • 2020-05-13
    • 1970-01-01
    相关资源
    最近更新 更多