简体   繁体   中英

Haskell labeling the nodes of a binary tree with my state monad does not work

So far I wrote the following code, I tested all the functions, and they work well, but testing the indexNodesM function, it just does not work, I think the put method is not working right.

The given test cases are:

execState (indexNodesM exTree1) 0 == 6
evalState (indexNodesM exTree1) 0 == Node (5,3) (Node (3,1) Leaf (Node (2,11) (Node (0,7) Leaf Leaf) (Node (1,5) Leaf Leaf))) (Node (4,13) Leaf Leaf)

For example, executing execState (indexNodesM exTree1) 0 gives 0 as result.

My code:

{-# LANGUAGE InstanceSigs #-}


import Control.Monad (ap)


newtype State s a = S { runState :: s -> (a,s) }

evalState :: State s a -> s -> a
evalState (S f) s = fst (f s)

execState :: State s a -> s -> s
execState (S f) s = snd (f s)

instance Functor (State s) where
 fmap :: (a -> b) -> (State s a) -> (State s b)
 fmap f (S g) = S (\n -> (f (fst (g (n))), n))

instance Applicative (State s) where
  pure  = return
  (<*>) = ap 

instance Monad (State s) where
 return :: a -> (State s a)
 return a = S (\n -> (a, n))
 (>>=) :: (State s a) -> (a -> State s b) -> (State s b)
 (>>=) (S f) g   = S (\n -> runState (g (fst (f n))) (n))

get :: State s s
get = S (\n -> (n, n))

put :: s -> State s ()
put x = S (\n -> ((),x))

modify :: (a -> a) -> State a ()
modify f = S (\n -> ((),  f n))

data Tree a = Leaf | Node a (Tree a) (Tree a)
  deriving (Eq, Ord, Show)

exTree1 :: Tree Int
exTree1 =
  Node 3
    (Node 1
      Leaf
      (Node 11
        (Node 7
          Leaf
          Leaf)
        (Node 5
          Leaf
          Leaf)))
    (Node 13
      Leaf
      Leaf)

indexNodesM :: Tree a -> State Int (Tree (Int, a))
indexNodesM Leaf = return Leaf
indexNodesM (Node x tree1 tree2) = do
 i <- get
 put (i + 1)
 t1 <- indexNodesM tree1
 t2 <- indexNodesM tree2
 return (Node (i, x) t1 t2)

What could be the problem? Thanks in advance.

Welcome to Stack Overflow. If you fix the definition of your State monad, then it will work as you expect. The problem with your current implementation is that neither >>= nor fmap actually update the state, as you always use fst to throw the state away and then use the old state. Here is the corrected implementation:

import Control.Monad (ap, liftM)

...

instance Functor (State s) where
 fmap = liftM

instance Applicative (State s) where
  pure  = return
  (<*>) = ap

instance Monad (State s) where
 return :: a -> (State s a)
 return a = S (\n -> (a, n))
 (>>=) :: (State s a) -> (a -> State s b) -> (State s b)
 (>>=) (S f) g   = S (\n -> let (a, n') = f n in runState (g a) n')

Now your test cases work almost as expected, except that indexNodesM labels the nodes from left to right:

*Main> execState (indexNodesM exTree1) 0 == 6
True

*Main> evalState (indexNodesM exTree1) 0
Node (0,3) (Node (1,1) Leaf (Node (2,11) (Node (3,7) Leaf Leaf) (Node (4,5) Leaf Leaf))) (Node (5,13) Leaf Leaf)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM