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 **.
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:
return a >>= k = k a
;m >>= return = m
; andm >>= (\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.