使用 >>= 将表达式转换为 do 表示法

Converting expression with >>= to do notation

我有以下代码

newtype State s a = State { runState :: s -> (s,a) }    
evalState :: State s a -> s -> a
evalState sa s = snd $ runState sa s

instance Functor (State s) where
  fmap f sa = State $ \s ->
    let (s',a) = runState sa s in
      (s',f a)

instance Applicative (State s) where
  pure a = State $ \s -> (s,a)

  sf <*> sa = State $ \s ->
    let (s',f) = runState sf s
        (s'',a) = runState sa s' in
      (s'', f a)

instance Monad (State s) where
  sa >>= k = State $ \s ->
    let (s',a) = runState sa s in
      runState (k a) s'

get :: State s s
get = State $ \s -> (s,s)

set :: s -> State s ()
set s = State $ \_ -> (s,())

bar (acc,n) = if n <= 0
              then return ()
              else
              set (n*acc,n-1)

f x = factLoop

factLoop =  get >>= bar >>= f

 runState factLoop (1,7)

给出 ((5040,0),())

我正在尝试编写函数

 factLoop =  get >>= bar >>= f

使用 do 表示法

我试过了

 factLoop' =  do
                (x,y) <- get 
                h <-  bar (x,y) 
                return ( f h) 

但这并没有给出正确的类型,应该是 State (Int, Int) ()

有什么想法吗?

谢谢!

只需删除最后一行的 return :

factLoop' =  do
                (x,y) <- get 
                h <-  bar (x,y) 
                f h

您的原始代码中没有 return,因此 do 表示法版本中也应该有 none。 do 符号只是 "translates" 使用 >>=,正如您已经完成的那样。

>>=infixl 1(左结合二元运算符),所以你真正拥有的是

f x = factLoop

factLoop =  get >>= bar >>= f
         =  (get >>= bar) >>= f
         =  (get >>= bar) >>= (\x -> f x)
         = do { x <- (get >>= bar)
              ; f x }
         = do { _ <- (get >>= bar)
              ; factLoop }
         = do { _ <- (get >>= (\x -> bar x))
              ; factLoop }
         = do { _ <- do { x <- get 
                        ; bar x }
              ; factLoop }
         = do { x <- get 
              ; _ <- bar x 
              ; factLoop }

最后一个是因为monad结合律("Kleisli composition forms a category")。

以不需要猜测的原则方式执行此操作。一段时间后,您当然会对此有所了解,但在您真正了解之前,保持正式会有所帮助。