Haskell IO缩进

Haskell IO indentation

我尝试重写该程序,它正在运行:

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 中的后缀项)

然后我尝试使用守卫:

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

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)

缩进规则乍一看可能令人费解,但实际上 .

我认为您当前的代码非常优雅 -- 我觉得它很好。

如果你想要更多选择,你可以使用 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)

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

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

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

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

(\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 }

只有当行可以保持较短并且要匹配的模式数量较少时,我才会使用它,否则可能难以阅读。