Haskell:理解if-else语句的do表示法

Haskell:理解if-else语句的do表示法,haskell,functional-programming,monads,equivalence,do-notation,Haskell,Functional Programming,Monads,Equivalence,Do Notation,我有以下用于操纵机器人的API代码: data Direction = Left | Right forward :: IO () blocked :: IO Bool turn :: Direction -> IO () 我试图理解两个程序,这两个程序将推动机器人前进,除非它被障碍物阻挡,在这种情况下,机器人应该转向正确的方向 但是,我不确定以下两个计划之间的区别是什么: -- program 1 robot = do detected <- blocked

我有以下用于操纵机器人的API代码:

data Direction = Left | Right
forward    :: IO ()
blocked :: IO Bool
turn       :: Direction -> IO ()
我试图理解两个程序,这两个程序将推动机器人前进,除非它被障碍物阻挡,在这种情况下,机器人应该转向正确的方向

但是,我不确定以下两个计划之间的区别是什么:

-- program 1
robot = do
  detected <- blocked
  if detected 
    then turn Right
    else forward
  robot

-- program 2
robot = do
  detected <- blocked
  if detected
    then turn Right
         robot
    else forward
         robot
——程序1
机器人

你说这两个程序是等价的,这是正确的。更一般地说,
如果cond然后(x>>动作)else(y>>动作)
等同于
(如果cond然后x else y)>>动作
。这是一个事实的结果,即
f(如果cond那么x else y)=如果cond那么(fx)else(fy)
;如果你采取
f=(>>action)
你就得到了单子的等价物。

你不需要
右转;机器人
在第二种情况下(
代表新线)?为什么一定要右转;程序二的机器人?需要它是因为要将多个IO操作粘合在一起吗?是的,对于您的版本,我不确定它为什么会编译。@ceno980因为if/then/else的then和else部分可以是任意表达式,所以它们使用正常的Haskell表达式语法。它们不是自动的
do
块语法,仅仅因为整个if/then/else发生在do块中。您需要对两个IO操作进行排序。一种方法是将它们写在
do
块的单独行上。在普通表达式语法中,将它们写在多行上并不能做到这一点;它的意思与在一条线上右转机器人的意思相同。如果你想要
do
语法,你需要启动一个新的
do
块。你怎么知道机器人是一个IO动作?这是因为IO操作是在do块中使用的吗?请注意,为了迂腐起见,您提到的规则仅适用于strict
f
。例如,
cond=undefined
f=\\\\\->()
违法。也就是说,
f=(>>action)
在IO monad中是严格的,所以一切都正常。谢谢@chi!我应该把它编辑到我的帖子里吗?不,我只是吹毛求疵。提到哈斯克尔应该遵守的法律是相当普遍的,但实际上只有在“道德”的意义上,如果我们忽略了这里和那里的底部。