【问题标题】:Handling nested if-else-then in do blocks in Haskell在 Haskell 的 do 块中处理嵌套的 if-else-then
【发布时间】:2019-09-12 05:21:51
【问题描述】:

我发现我不知道如何处理 Haskell 中 do-blocks 中嵌套的 if-else-then

我已经知道我可以使用case,但这需要我的所有条件(abc)返回相同的类型(Bool,所以只有两个案例,但我需要三个不同的案例),因此不是一般的(如果我错了,请纠正我)。我也尝试过考虑在这里使用守卫,但我不知道如何在do 语句中进行这项工作,尤其是如果-- something 表达式的类型是IO ()

假设我在do 中有以下代码:

if a then
     -- something
else 
    if b then
        -- something
    else
        if c then
            -- something
        else
            -- something

我如何创建等效逻辑但没有所有缩进?

【问题讨论】:

  • 您所写的内容已经要求您所有的-- something 占位符返回相同的类型,因此您对case 的反对并不真正适用。
  • (1) “这将要求我所有的案例都返回相同的类型,因此不是一般的(如果我错了,请纠正我)”——你还必须返回相同的类型if 表达式的两个分支。除了语法之外,Bool 上的 if 表达式和 case 表达式之间基本上没有区别。 (2)“我也尝试过考虑在这里使用守卫,但我不知道如何在 do 语句中进行这项工作”——你不能在 do-block 中使用守卫; if 表达式确实是正确的选择。
  • 对不起,我在最初的问题中说错了,这不是 -- something 占位符返回我试图避免的相同类型,而是条件(ab 和 @ 987654339@)。我已经编辑了我的答案。

标签: haskell


【解决方案1】:

首先,值得注意的是 if 表达式实际上不需要额外的缩进(if-within-do 曾经是一个例外,但 Haskell 2010 消除了这一点)。这意味着您可能会折叠所有额外的缩进:

test = do
    len <- length <$> getLine
    if len < 4
    then putStrLn "Short"
    else if len > 6
    then putStrLn "Long"
    else putStrLn "Mid"

不过,就我个人而言,我觉得这在美学上并不太讨人喜欢,因为我觉得 一些缩进让 if 表达式更容易理解。一个不错的选择是使用the MultiWayIf extension:

{-# LANGUAGE MultiWayIf #-}

test = do
    len <- length <$> getLine
    if | len < 4 -> putStrLn "Short"
       | len > 6 -> putStrLn "Long"
       | otherwise -> putStrLn "Mid"

最后一点,嵌套的 if 表达式变得笨拙可能是一个很好的机会,可以将事物分解为单独的定义,或者以其他方式重新组织您的代码。另见:How do I deal with many levels of indentation?

【讨论】:

  • 谢谢!这正是我正在寻找的答案。很抱歉我在原始问题中的错字。到目前为止,Haskell 非常有趣!
  • @Utagai 不客气,不用担心——如果你只知道我的帖子中有多少错别字... :)
  • @Utagai,如果你不想使用MultiWayIf,你可以使用case () of _ | ...。更丑陋,但标准。
  • 谢谢@dfeuer,我没有意识到我可以像这样使用case,但是阅读它,我明白它为什么有效。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-31
  • 1970-01-01
  • 2012-03-09
相关资源
最近更新 更多