Haskell IO отступ - PullRequest
       13

Haskell IO отступ

0 голосов
/ 12 января 2019

Я пытался переписать ту программу, которая работает:

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 в 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.)

Источник примера: там

Решения: Есть

Ответы [ 2 ]

0 голосов
/ 14 января 2019

Другим вариантом является встроенное сопоставление с образцом для типов сумм Это хорошо, если у вас есть небольшой фрагмент кода и вы не хотите использовать несколько строк.

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 }

Я бы использовал это, только если строки могут быть короткими, и у вас есть небольшое количество шаблонов для сопоставления, в противном случае это может быть трудно для чтения.

0 голосов
/ 12 января 2019

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, даже если большинство Haskellers предпочли бы охранников. (Лично у меня нет реальных предпочтений)

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)

Я не утверждаю, что стиль в подавляющем большинстве случаев лучше, чем другой.

...