Вопрос

Я написал функцию Haskell, которая вычисляет факторию каждого числа в данном списке и печатает ее на экране.

factPrint list =
if null list
    then putStrLn ""
    else do putStrLn ((show.fact.head) list)
        factPrint (tail list)

Функция работает, но я нахожу третью строку немного запутанной. Почему компилятор (GHC) не сообщил об ошибке, поскольку нет «Do» до функции «Putstrln» (Quasi?)? Если я опускаю «DO» из 4 -й строки, появляется ошибка, как и ожидалось.

Я совершенно новичок в Хаскелле и его пути, поэтому, пожалуйста, простите меня, если я сказал что -то слишком глупое.

Это было полезно?

Решение

do putStrLn ((show.fact.head) list)
   factPrint (tail list)

на самом деле еще один способ написания

putStrLn ((show.fact.head) list) >> factPrint (tail list)

что, в свою очередь, означает

putStrLn ((show.fact.head) list) >>= \_ -> factPrint (tail list)

А do Нотация - это удобный способ объединения этих монад без этого другого уродливого синтаксиса.

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

Другие советы

Если вы новичок в Haskell, подумайте о do как аналогично требуемым скобкам после if на C-подобном языке:

if (condition)
  printf("a"); // braces not required
else {
  printf("b"); // braces required
  finish();
}

do работает так же в Хаскелле.


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

factPrint :: [Int] -> IO ()
factPrint [] = putStrLn ""
factPrint list = do
  putStrLn (show.fact.head) list
  factPrint (tail list)

Итак, если отпечаток факта возвращает IO (), и тип putStrLn "" является IO (), тогда это совершенно законно для factPrint [] равному putStrLn "". Анкет Нет do Требуется-на самом деле вы можете просто сказать factPrint [] = return () Если вы не хотите, чтобы Trainling Newline.

do используется, чтобы связать несколько монадических выражений вместе. Это не влияет, когда следует только одно выражение.

Для того, чтобы быть хорошо сформированным, необходимо лишь, чтобы тогдашнее оказание и Else-Clause имели один и тот же тип. Поскольку оба положения имеют тип IO () В этом случае.

Ключевое слово DO используется для секвенирования, if-then-else в Haskell не должен содержать do вообще, если каждая ветвь является единственным оператором, например.

if a
  then b
  else c

Вам нужен do В вашем примере, когда вы секвенируете две операции в вашей ветви. Если вы опустите do тогда factPrint(tail list) Считается, что утверждение не является частью функции, и, таким образом, компилятор жалуется, когда оно сталкивается с неожиданным утверждением.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top