【问题标题】:Haskell IO indentationHaskell IO 缩进
【发布时间】:2019-01-12 14:04:08
【问题描述】:

我试图重写那个程序,它正在工作:

nameIOite :: IO ()
nameIOite = do
    putStrLn "What's your name ?"
    name <- getLine
    if name `elem` ["Simon","John","Phil"]
  --if name == "Simon" || name == "John" || name == "Phil" also works but is ugly.   
        then putStrLn "I think Haskell is a great programming language."
        else if name == "Koen"
            then putStrLn "I think debugging Haskell is fun."
            else putStrLn "I don't know your name."

这是使用 if/then/else 完成的(因此是nameIOite 中的后缀ite)

然后我尝试使用警卫:

nameIOg :: IO ()
nameIOg = do
    putStrLn "What's your name ?"
    name <- getLine
    let answer
        | name `elem` ["Simon","John","Phil"]   = "I think Haskell is a great programming language."
        | name == "Koen"                        = "I think debugging Haskell is fun."
        | otherwise                             = "I don't know your name."
    putStrLn answer

这不起作用:

test.hs:6:9: error:
parse error (possibly incorrect indentation or mismatched brackets)
  |
6 |    | name `elem` ["Simon","John","Phil"]   = "I think Haskell is   a great programming language."
  |    ^
Failed, no modules loaded.

经过一些实验,结果证明解决方案再次缩进警卫(我根本不清楚):

nameIOg :: IO ()
nameIOg = do
    putStrLn "What's your name ?"
    name <- getLine
    let answer
            | name `elem` ["Simon","John","Phil"]   = "I think Haskell is a great programming language."
            | name == "Koen"                        = "I think debugging Haskell is fun."
            | otherwise                             = "I don't know your name."
    putStrLn answer

Ok, one module loaded.

双缩进是从哪里来的,有没有办法写得更优雅?

(顺便说一句,我在查看我的 wikibook.hs 文件时偶然发现了这一点。)

示例来源:there

解决方案:there

【问题讨论】:

  • 还要注意,额外的缩进可以是一个空格——只要|s 在a 的右边至少有一个字符,这应该可以工作。

标签: haskell io guard-statement


【解决方案1】:

let 允许多个定义,如

main = do
   doSomething
   let x = 1
       y = 2
       z = 3
   print (x+y+z)

注意缩进。 y = 2 未解析以继续定义 x = 1,因为它从同一列开始。

如果你想解析一个新行,就好像它延续了前一行,你必须缩进更多。例如

main = do
   doSomething
   let x | someCondition = 1
         | otherwise     = 0   -- more indented
       y = 2
       z = 3
   print (x+y+z)

或者,使用另一行

main = do
   doSomething
   let x
          | someCondition = 1   -- more indented
          | otherwise     = 0   -- more indented
       y = 2
       z = 3
   print (x+y+z)

缩进规则起初可能看起来令人费解,但实际上它们是 quite simple.

我认为您当前的代码尽可能优雅 -- 对我来说看起来不错。

如果您想要更多选择,您可以使用if then else,即使大多数 Haskeller 更喜欢守卫。 (就个人而言,我没有真正的偏好)

main = do
   doSomething
   let x = if condition               then 1
           else if someOtherCondition then 0
           else                            -1
       y = 2
       z = 3
   print (x+y+z)

您也可以使用另一行,例如(我更喜欢那个)

main = do
   doSomething
   let x =
          if condition               then 1
          else if someOtherCondition then 0
          else                            -1
       y = 2
       z = 3
   print (x+y+z)

甚至

main = do
   doSomething
   let x =
          if condition
          then 1
          else if someOtherCondition
          then 0
          else -1
       y = 2
       z = 3
   print (x+y+z)

我并不是说一种风格绝对优于另一种风格。

【讨论】:

    【解决方案2】:

    另一个选项是 sum 类型的内联模式匹配。如果您有一小段代码并且不想使用多行代码,这很好。

    z <- maybeDoSomething :: IO (Maybe Int)
    let x = case z of { Nothing -> 0; Just v -> v }
    

    它还可以缩短匿名函数中模式匹配所需的空间。这个:

    (\x -> case t of
             Nothing -> 0
             Just v  -> v
    )
    

    可以改成这样:

    (\x -> case t of { Nothing -> 0; Just v  -> v })
    

    你也可以避开if-then-else。

    t <- didSomethingSucceed :: IO Bool
    let x = case t of { True -> 1; False -> 0 }
    

    如果行可以保持简短并且您有少量模式要匹配,我只会使用它,否则可能难以阅读。

    【讨论】:

      猜你喜欢
      • 2019-03-28
      • 1970-01-01
      • 1970-01-01
      • 2020-02-03
      • 2012-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多