【问题标题】:Haskell: Understanding do notation with if-else statementsHaskell:用 if-else 语句理解 do 表示法
【发布时间】:2019-12-04 09:33:54
【问题描述】:

我有以下代码用于操作机器人的 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

detected &lt;- blocked 行将布尔值从 IO 中取出。如果条件if detected 评估为真,则机器人向右转,否则机器人向前移动。在程序 1 中,机器人功能在向右或向前移动后再次被调用。程序2中,函数robot在右转或前进后直接调用。

我不确定在 if-else 语句(在程序 1 中)之后调用机器人与在程序 2 中的 thenelse 案例中调用它有什么区别。我说这两个是否正确程序是等价的吗?任何见解都值得赞赏。

【问题讨论】:

  • 第二种情况不需要do turn Right; robot吗(;代表换行)?
  • 为什么一定要右转;程序二的机器人?是否需要它,因为为了将多个 IO 操作粘合在一起?
  • 是的,对于您的版本,我不确定它为什么会编译。
  • @ceno980 因为 if/then/else 的 then 和 else 部分可以是任意表达式,所以它们使用普通的 Haskell 表达式语法。它们不会自动成为 do 块语法,因为整个 if/then/else 恰好发生在 do 块中。您想要对两个 IO 操作进行排序。一种方法是将它们写在do 块的不同行上。在普通的表达式语法中,将它们写在多行上并不能做到这一点。它与turn Right robot 在一行上的含义相同。如果你想要do 语法,你需要开始一个新的do 块。
  • 怎么知道robot是一个IO动作?是因为在do块中使用了IO动作吗?

标签: haskell functional-programming monads equivalence do-notation


【解决方案1】:

你说这两个程序是等价的是正确的。更一般地,if cond then (x &gt;&gt; action) else (y &gt;&gt; action) 等价于 (if cond then x else y) &gt;&gt; action。这是f (if cond then x else y) = if cond then (f x) else (f y); 的结果。如果你使用f = (&gt;&gt; action),你会得到 monads 的等价物。

【讨论】:

  • 请注意,为了迂腐,您提到的法律仅适用于 strict f。例如。 cond = undefinedf = \_ -&gt; () 违法。话虽如此,f = (&gt;&gt; action) 在 IO monad 中是严格的,所以一切正常。
  • 感谢@chi 的指正!我应该将其编辑到我的帖子中吗?
  • 不,我只是在吹毛求疵。提到在 Haskell 中应该成立的规律是相当普遍的,但实际上只是在“道德”意义上这样做,如果我们在这里和那里忽略底部。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-13
  • 1970-01-01
相关资源
最近更新 更多