haskellmonads

difficulty to define the monad on all values


I trying to write monad that multiply all data nodes by given number. I don't know how to define the Monad correctly.

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)))

I get error-

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)
   |                                       ^^^^^^^^^^

What do I need to fix here? The problem is on the line that is with **.


Solution

  • The type system will complain, since the "bind" operator >>= has signature:

    (>>=) :: Monad m => m a -> (a -> m b) -> m b

    So let us specialize the signature for the LinkedList:

    (>>=) :: LinkedList a -> (a -> LinkedList b) -> LinkedList b

    So the function takes at the left side a LinkedList a, and at the right side a function that maps an a (!) to a LinkedList b, and we expect the outcome to be a LinkedList b. The function you have defined can not do that: since if you construct a Node (f a) (next >>= f), the result will be a LinkedList (LinkedList b). Indeed, you apply f to a (the head of the list), which yields a LinkedList b (as head of the Node).

    If we look at the signature above, there are perhaps some ideas that might come up, but the most straightforward idea, is probably to implement some sort of concatMap :: [a] -> (a -> [b]) -> [b]. The "bind" has to satisfy the following rules:

    1. return a >>= k = k a;
    2. m >>= return = m; and
    3. m >>= (\x -> k x >>= h) = (m >>= k) >>= h.

    the concatMap function satisfies the three constraints. (1) If we wrap a value x into a LinkedList, and apply f on every element (of the singleton list), we will obtain a list that contains one list, that of the result of k a, but by using the concat of concatMap, we flatten this again. (2) If we would use m >>= return with concat, we will wrap every element in a new singleton list, but the concatenation, will unwrap it again.

    So we can implement it as:

    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)
    

    So here build will iterate through the LinkedList produced by f a, and basically construct an almost duplicate, except that when we reach the end, we will continue with the concatenation of the outcome of the bind of the remaining elements.