【问题标题】:Why does Data.Tree.Tree not have a monoid instance?为什么 Data.Tree.Tree 没有幺半群实例?
【发布时间】:2019-09-24 14:44:29
【问题描述】:

我意识到答案可能是存在多个有效的此类实例(例如整数;总和、乘积......)。也许有人有比这更令人满意的答案?

正如 Joachim Breitner 在此答案 How do you implement monoid interface for this tree in haskell? 中出色解释的那样,任何应用程序都有一个 monoid 实例:

mempty :: Applicative f => Monoid a => f a
mempty = pure mempty

mappend :: Applicative f => Monoid a => f a -> f a -> f a
mappend f g = mappend <$> f <*> g

所以我想知道为什么containers 中的Data.Tree.Tree 没有这样的实例?相同的参数可以用于任何其他没有伴随 monoid 实例的 monad。在我看来,他们应该有这样的例子是很自然的。也许情况并非如此。希望有人能赐教。

我想另一个原因可能是我为树提出的实例不是“有用的”。在我看来,这与多个有效实例的论点一样令人不满意。

【问题讨论】:

  • “非空的,可能是无限的,多路树;也称为玫瑰树。” - 我不认为 mempty 可以存在,但可能是错误的。
  • 一棵树是Foldable 的一个实例,所以我想这可能会提供一些工具来处理具有属于Monoid 实例类型的值的三元组。但我同意将树也设为Monoid 的实例可能是有意义的。
  • @Caramiriel:如果它包装的项目也是Monoid,我们可以将其定义为mempty = Node mempty []
  • 你的mappend定义等同于liftA2 mappend,就像Apdefines一样。
  • @fredefox, liftA2 组合更干净。 liftA2 . liftA2 . liftA2 表达了在多个函子下提升的想法。

标签: haskell


【解决方案1】:

我不知道为什么它不可用。但是,您建议的实例可以通过 Ap 新类型一劳永逸地使用,它提供了一个 instance (Applicative f, Monoid m) =&gt; Monoid (Ap f m)。所以如果你需要你写的实例,你可以用这个得到它,即使它在裸 Tree 类型上不存在。

【讨论】:

  • 啊,我明白了。 Ap “见证” Joachim Breitner 提到的观察结果。我不知道这种类型。那么,我想知道什么时候有资格作为“自然”幺半群实例,例如对于[]mappend = (++) 以及当我们使用SumProductAp 等“自然模棱两可”时。人。来自Data.Monoid。不过,仔细观察Data.Monoid 肯定有用。感谢您的提示!
  • @fredefox 我认为这基本上是主观的。我会使用的标准是“如果我告诉你这种类型有一个 monoid 实例但没有告诉你它是如何工作的,你会立即知道该实例可能做什么吗?”。但是对于那些只熟悉类型/库的人来说,这个问题的答案与大量使用它的人有很大的不同。最终,我们只是受制于编写库的人的判断,但通常可以通过新类型解决我们不同意的决定,所以我认为没有人会为此失眠。
  • 除非你是像我这样的固执者,否则我猜 ;) 但说真的,我认为这是一个非常好的观察结果。设计原则可能是实例应该立即显而易见(在库设计的情况下)或由用例驱动(在应用程序代码的情况下)。我想类型类和同上连贯性与它们所代表的数学概念有点不一致,这只是生活中的一个事实。我的意思是,它实际上是小工具(Nat, (+), 0, ...laws),它一个幺半群和类似的(Nat, (*), 1, ...laws),而不是——正如我们喜欢假装的——Nat本身。
【解决方案2】:

有多个有效实例。 Tree 还支持“zippy”Applicative 及其对应的基于 Ap 的 monoid:

instance Applicative Tree where
  pure a = let t = Node a (repeat t) in t
  liftA2 f (Node a as) (Node b bs) =
    Node (f a b) (zipWith (liftA2 f) as bs)

instance Semigroup a => Semigroup (Tree a) where
  Node a as <> Node b bs =
    Node (a <> b) (zipWith (<>) as bs)

instance Monoid a => Monoid (Tree a) where
  mempty = Node mempty (repeat mempty)

我不知道哪个实例(如果有的话)实际上是有用的。


只是为了好玩,这里有一个有点傻的,它只是将构造函数提升到底层的幺半群上:

instance Semigroup a => Semigroup (Tree a) where
  Node a as <> Node b bs = Node (a <> b) (as ++ bs)

instance Monoid a => Monoid (Tree a) where
  mempty = Node mempty []

【讨论】:

    猜你喜欢
    • 2014-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-12
    • 1970-01-01
    • 1970-01-01
    • 2016-08-01
    • 1970-01-01
    相关资源
    最近更新 更多