1

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

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 完成的(因此后缀 ite in 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 文件时偶然发现了这一点。)

例子来源:那里

解决方案:

4

2 回答 2

4

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)

我并不是说一种风格比另一种风格要好得多。

于 2019-01-12T14:31:57.053 回答
0

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

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-01-14T05:00:25.337 回答