【问题标题】:Haskell labeling the nodes of a binary tree with my state monad does not workHaskell 用我的状态单子标记二叉树的节点不起作用
【发布时间】:2020-04-19 20:30:39
【问题描述】:

到目前为止,我写了以下代码,我测试了所有功能,它们运行良好,但测试 indexNodesM 函数,它不起作用,我认为 put 方法不起作用。

给定的测试用例是:

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)

例如,执行execState (indexNodesM exTree1) 0 会得到 0 作为结果。

我的代码:

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

可能是什么问题?提前致谢。

【问题讨论】:

  • 欢迎来到 SO!究竟什么不起作用?请澄清您的问题并解释您的代码试图实现的目标。
  • 您好!我尝试自己实现状态单子,这似乎可行,并且在 indexNodesM 函数中我想标记二叉树的节点,但结果,所有节点都标有起始状态,例如:如果我执行 evalState (indexNodesM exTree1) 0 ,然后所有节点都标记为 0,但它应该用越来越多的数字标记,比如 0, 1, 2, 3 .. 等。我猜 put 方法有问题,因为它不会更新 indexNodesM 函数中的状态。
  • 因为你的状态单子“似乎有效”根本不起作用。你的函子和你的单子定义都被破坏了,实际上根本没有传递状态。
  • 您之前在stackoverflow.com/q/61306856/7509065 中提出过此问题,但随后将其删除。您应该取消删除它并重新编辑其他详细信息,而不是创建新问题。
  • 忘掉其余的复杂性,尝试通过execState (const () &lt;$&gt; put True) False 之类的简单测试使状态monad 工作。你得到了什么?你认为你应该得到什么?现在跟踪您的代码,看看它为什么不同。

标签: haskell binary label state monads


【解决方案1】:

欢迎来到 Stack Overflow。如果您修复了 State monad 的定义,那么它将按您的预期工作。您当前实现的问题是 &gt;&gt;=fmap 都没有实际更新状态,因为您总是使用 fst 丢弃状态然后使用旧状态。这是更正后的实现:

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

现在您的测试用例几乎可以按预期工作,除了 indexNodesM 从左到右标记节点:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-01
    • 1970-01-01
    • 2020-02-07
    • 2012-03-26
    • 1970-01-01
    相关资源
    最近更新 更多