Haskell ЕСЛИ иначе

input <- readLn
 if (input == 0)
 then 
  putStr  "0" 
 else if (input ==1)
then 
  putStr  "1" 
else if (input ==2)

в таком сценарии, как использовать несколько putStr с then или else if?

когда я пытаюсь получить ошибку

Type error in application
*** Expression     : putStr "0" putStr "0"
*** Term           : putStr
*** Type           : String -> IO ()
*** Does not match : a -> b -> c -> d

person Sudantha    schedule 08.06.2011    source источник
comment
Это не отвечает на ваш вопрос, но я надеюсь, вы понимаете, что это лучше написать как сопоставление с образцом. case input of 0 -> … 1 -> …   -  person Chuck    schedule 08.06.2011
comment
@Chuck IO с сопоставлением шаблонов, возможно ли это, потому что это программа ввода-вывода   -  person Sudantha    schedule 09.06.2011


Ответы (3)


Используйте do-обозначение:

do
  a <- something
  if a 
  then
    do
      cmd1
      cmd2
  else
    do
      cmd3
      cmd4
  cmd5 -- this comes after the 'then' and the 'else'
person Lambdageek    schedule 08.06.2011
comment
Я предпочитаю помещать do в одну строку вместе с else и then. - person fuz; 08.06.2011
comment
@FUZxxl Верно, я тоже. Но я хотел подчеркнуть, что это не какой-то магический then do синтаксис. Это просто обычная do-нотация внутри ветвей выражения if-then-else. - person Lambdageek; 08.06.2011
comment
я использовал только do в начале класса .. этот подход решил проблему - person Sudantha; 09.06.2011

Каноническое объяснение этого состоит в том, что вы хотите сформировать новое монадическое значение из двух существующих. Давайте посмотрим на тип putStr,

IO ()

Это означает, что это некий черный ящик, который при выполнении «вернет» (единственное и единственное) значение типа единицы измерения. Ключевая идея монадических вычислений заключается в том, что у вас есть комбинатор >>=, который будет объединять два монадических выражения, передавая результат одного в следующее (точнее, функцию, которая создает следующее). Одним из важных моментов является то, что библиотека IO предоставляет этот комбинатор, а это означает, что

  • Это [IO в данном случае] может пропустить второе монадическое значение, например, когда первое выдает исключение.
  • Он может передавать другие данные, в случае IO состояния RealWorld, содержащего дескрипторы открытых файлов и т. д.
  • Он может «гарантировать», что первый оценивается первым, в отличие от большинства вычислений лямбда-выражений, где самые внешние («последние») термины расширяются первыми. Это важно для печати, где первая печать должна сначала изменить мир.

В вашем случае используйте это так,

putStr "0" >>= (\c -> putStr "0")

Есть короткий путь, конечно,

putStr "0" >> putStr "0"

и do-нотация, как упоминалось другим плакатом, которая является еще большим синтаксическим сахаром,

do
    putStr "0"
    putStr "0"
person gatoatigrado    schedule 08.06.2011
comment
Небольшое замечание по поводу терминологии: слово монада, используемое как существительное без других определителей, обычно относится только к конструкторам типов, которые имеют экземпляр Monad. Значения некоторого типа m a, где m — монада, обычно называются как-то иначе. - person C. A. McCann; 08.06.2011
comment
@camccann, что касается терминологии: я видел команды и действия. Как и в putStr s, это действие IO, которое печатает строку s. - person Lambdageek; 08.06.2011
comment
@Lambdageek: это хорошо для IO и некоторых других, но звучит глупо применительно к чему-то вроде списков. Кажется, что в общем случае используются вариации чего-то вроде монадического значения, но это очень неуклюже. - person C. A. McCann; 08.06.2011
comment
Мне больше нравится монадическое значение, чем действие. Я отредактирую запись, когда мы придем к согласию. - person gatoatigrado; 08.06.2011
comment
@gatoatigrado: Увы, если бы существовал общеупотребительный термин общего назначения, я бы так и сказал. Я бы предложил либо действие конкретно для IO, либо что-то несуразное, например монадическое значение или значение в монаде в целом. Но только монада может создать путаницу. Я помню, как кто-то предложил мотылька, что очень мило, но я не думаю, что оно прижилось. :) - person C. A. McCann; 08.06.2011

Для этого надуманного примера вы также можете использовать случай, например:

main = readLn >>= \input -> case input of
    0 ->    putStrLn "0"

    1 ->    putStrLn "0"

    2 ->    putStr   "0" 
         >> putStrLn "0"

    3 ->    putStr   "0"
         >> putStr   "0"
         >> putStrLn "0"

    _ ->    putStrLn "infinite"

Возможно, это могло бы быть более читабельным с синтаксисом do, но я хотел сначала показать его без синтаксиса do, просто чтобы подчеркнуть, что do-syntax — это просто синтаксис и на самом деле ничего особенного не делает. Вот это с do-синтаксисом.

main = do
    input <- readLn
    case input of
        0 -> putStrLn "0"

        1 -> putStrLn "0"

        2 -> do putStr   "0" 
                putStrLn "0"

        3 -> do putStr   "0"
                putStr   "0"
                putStrLn "0"

        _ -> putStrLn "infinite"
person Barend Venter    schedule 08.06.2011