难以在所有值上定义monad

时间:2017-12-06 17:21:30

标签: haskell

我尝试编写monad,将所有数据节点乘以给定的数字。 我不知道如何正确定义Monad。

module Main where  
data LinkedList a = NodeWithoutNext a | Node a (LinkedList a) deriving (Show)

instance Functor LinkedList where
  fmap f (NodeWithoutNext x) = NodeWithoutNext (f x)
  fmap f (Node a next) = Node (f a) (fmap f next)

instance Applicative LinkedList where
   pure = NodeWithoutNext
   (NodeWithoutNext f) <*> (NodeWithoutNext x) = NodeWithoutNext (f x)
   (NodeWithoutNext f) <*> (Node a next) = Node (f a) (fmap f next)

instance Monad LinkedList where
   return = NodeWithoutNext
   (NodeWithoutNext a) >>= f = f a
   **(Node a next) >>= f =  Node (f a) (next >>= f)**

main :: IO ()
main  =  do  
    let list = Node 3 (Node 2 (NodeWithoutNext 7))
    print (list)
    print (list >>= (\x -> NodeWithoutNext (x+200)))

我收到错误 -

Bla.hs:16:39: error:
    * Couldn't match type `b' with `LinkedList b'
      `b' is a rigid type variable bound by
        the type signature for:
          (>>=) :: forall a b.
                   LinkedList a -> (a -> LinkedList b) -> Linked
        at Bla.hs:15:24-26
      Expected type: LinkedList (LinkedList b)
        Actual type: LinkedList b
    * In the second argument of `Node', namely `(next >>= f)'
      In the expression: Node (f a) (next >>= f)
      In an equation for `>>=':
          (Node a next) >>= f = Node (f a) (next >>= f)
    * Relevant bindings include
        f :: a -> LinkedList b (bound at Bla.hs:16:22)
        (>>=) :: LinkedList a -> (a -> LinkedList b) -> LinkedLi
          (bound at Bla.hs:15:24)
   |
16 |    (Node a next) >>= f =  Node (f a) (next >>= f)
   |                                       ^^^^^^^^^^

我需要在这里解决什么? 问题在于**。

1 个答案:

答案 0 :(得分:3)

类型系统会抱怨,因为“绑定”运算符Si具有签名:

>>=

因此,让我们专门针对(>>=) :: Monad m => m a -> (a -> m b) -> m b

的签名
LinkedList

因此该函数在左侧显示(>>=) :: LinkedList a -> (a -> LinkedList b) -> LinkedList b,在右侧显示将LinkedList a(!)映射到a的函数,我们希望结果为是LinkedList b。您定义的函数不能这样做:因为如果构造LinkedList b,结果将是Node (f a) (next >>= f)。实际上,您将LinkedList (LinkedList b)应用于f(列表的头部),这会产生a(作为LinkedList b的头部。)

如果我们查看上面的签名,可能会出现一些想法,但最直接的想法可能是实现某种Node。 “绑定”必须满足以下规则:

  1. concatMap :: [a] -> (a -> [b]) -> [b];
  2. return a >>= k = k a;和
  3. m >>= return = m
  4. m >>= (\x -> k x >>= h) = (m >>= k) >>= h函数满足三个约束。 (1)如果我们将值concatMap包装到x中,并在每个元素(单例列表)上应用LinkedList,我们将获得一个包含一个列表的列表, f的结果,但通过使用k a的{​​{1}},我们再次将其展平。 (2)如果我们将concat与concat一起使用,我们将把每个元素包装在一个新的单例列表中,但是连接将再次打开它。

    因此我们可以将其实现为:

    concatMap

    所以这里m >>= return将遍历instance Monad LinkedList where return = NodeWithoutNext (NodeWithoutNext a) >>= f = f a (Node a next) >>= f = build (f a) where build (NodeWithoutNext x) = (Node x (next >>= f)) build (Node x xs) = Node x (build xs) 生成的build,基本上构建一个几乎重复,除了当我们到达终点时,我们将继续联合其余要素的结果。