你如何在haskell中为这棵树实现monoid接口?

时间:2013-02-24 18:03:36

标签: haskell functional-programming monoids

请原谅这个术语,我的思绪还在弯曲。

树:

data Ftree a = Empty | Leaf a | Branch ( Ftree a ) ( Ftree a )
    deriving ( Show )

我有几个问题:

  1. 如果Ftree不能Empty,则不再是Monoid,因为没有身份值。

  2. 您如何使用此树实现mappend?你能不能随意嫁接两棵树吗?

  3. 对于二叉搜索树,您是否必须反省两棵树中的一些元素,以确保mappend的结果仍然是BST?

  4. 为了记录,其他一些东西Ftree可以在这里做:

    instance Functor Ftree where
        fmap g Empty             = Empty
        fmap g ( Leaf a )        = Leaf ( g a )
        fmap g ( Branch tl tr )  = Branch ( fmap g tl ) ( fmap g tr )
    
    instance Monad Ftree where 
        return             = Leaf
        Empty        >>= g = Empty
        Leaf a       >>= g = g a
        Branch lt rt >>= g = Branch ( lt >>= g ) ( rt >>= g )
    

1 个答案:

答案 0 :(得分:10)

你的问题有三个答案,一个是挑剔的,一个是无益的,一个是抽象的:

挑剔的回答

instance Monoid (Ftree a) where
    mempty = Empty
    mappend = Branch

这是Monoid类型类的实例,但不满足任何必需的属性。

无益的答案

你想要什么Monoid?只是在没有进一步信息的情况下要求一个monoid实例就像是在不提出问题的情况下寻求解决方案。有时会有一个自然的幺半群实例(例如列表)或只有一个(例如(),忽略定义问题)。我不认为这是这种情况。

顺便说一下:如果你的树在内部节点有递归组合两棵树的数据,会有一个有趣的monoid实例......

抽象答案

由于您提供了Monad (Ftree a)个实例,因此有一种获取Monoid实例的通用方法:

instance (Monoid a, Monad f) => Monoid (f a) where
    mempty = return mempty
    mappend f g = f >>= (\x -> (mappend x) `fmap` g)

让我们检查一下这是否是一个Monoid。我使用<> = mappend。我们假设Monad法律成立(我没有检查您的定义)。此时,请回忆Monad laws written in do-notation

我们的mappend用do-Notation编写,是:

mappend f g = do
  x <- f
  y <- g
  return (f <> g)

所以我们现在可以验证幺半群定律:

左侧身份

mappend mempty g
≡ -- Definition of mappend
do 
  x <- mempty
  y <- g
  return (x <> y)
≡ -- Definition of mempty
do 
  x <- return mempty
  y <- g
  return (x <> y)
≡ -- Monad law
do 
  y <- g
  return (mempty <> y)
≡ -- Underlying monoid laws
do 
  y <- g
  return y
≡ -- Monad law
g

正确的身份

mappend f mempty 
≡ -- Definition of mappend
do
  x <- f
  y <- mempty
  return (x <> y)
≡ -- Monad law
do
  x <- f
  return (x <> mempty)
≡ -- Underlying monoid laws
do 
  x <- f
  return x
≡ -- Monad law
f

最后是重要的结合法

mappend f (mappend g h)
≡ -- Definition of mappend
do
  x <- f
  y <- do
    x' <- g
    y' <- h
    return (x' <> y')
  return (x <> y)
≡ -- Monad law
do
  x <- f
  x' <- g
  y' <- h
  y <- return (x' <> y')
  return (x <> y)
≡ -- Monad law
do
  x <- f
  x' <- g
  y' <- h
  return (x <> (x' <> y'))
≡ -- Underlying monoid law
do
  x <- f
  x' <- g
  y' <- h
  return ((x <> x') <> y')
≡ -- Monad law
do
  x <- f
  x' <- g
  z <- return (x <> x')
  y' <- h
  return (z <> y')
≡ -- Monad law
do
  z <- do
    x <- f
    x' <- g
    return (x <> x')
  y' <- h
  return (z <> y')
≡ -- Definition of mappend
mappend (mappend f g) h

因此,对于每个(正确的)Monad(甚至对于每个应用程序仿函数,正如Jake McArthur在#haskell上指出的那样),都有一个Monoid实例。它可能是也可能不是您正在寻找的那个。