Пример цикла while в Haskell с использованием монад

Я хочу написать цикл в haskell, используя монады, но мне трудно понять концепцию.

Может ли кто-нибудь предоставить мне один простой пример цикла while, когда выполняются некоторые условия, которые включают действие ввода-вывода? Мне нужен не абстрактный пример, а реальный, конкретный, работающий.


person domoremath    schedule 13.02.2017    source источник
comment
Помогает ли этот вопрос?   -  person Mephy    schedule 14.02.2017
comment
Возможный дубликат цикла While в Haskell с условием   -  person jberryman    schedule 14.02.2017
comment
Я уже видел это, но есть ли что-то еще проще, где я могу легко сказать, что программа пытается вычислить сразу.   -  person domoremath    schedule 14.02.2017
comment
У вас есть пример императивного цикла, который вы не можете преобразовать?   -  person Lee    schedule 14.02.2017
comment
@Lee Скажите что-нибудь очень простое, например, если какое-то условие выполнено, вы продолжаете печатать, обновляя условие. Мне не нужна прямая рекурсия, а что-то с использованием монад.   -  person domoremath    schedule 14.02.2017


Ответы (1)


Ниже приведен ужасный пример. Вы были предупреждены.

Рассмотрим псевдокод:

var x = 23
while (x != 0) {
   print "x not yet 0, enter an adjustment"
   x = x + read()
}
print "x reached 0! Exiting"

Вот его пошаговый перевод на Haskell, максимально используя императивный стиль.

import Data.IORef

main :: IO ()
main = do
   x <- newIORef (23 :: Int)
   let loop = do
          v <- readIORef x
          if v == 0
          then return ()
          else do
             putStrLn "x not yet 0, enter an adjustment"
             a <- readLn
             writeIORef x (v+a)
             loop
   loop
   putStrLn "x reached 0! Exiting"

Это действительно ужасный Haskell. Он имитирует цикл while, используя рекурсивно определенный loop, что не так уж плохо. Но он везде использует ввод-вывод, в том числе для имитации изменяемых переменных в императивном стиле.

Лучшим подходом может быть удаление этих IORef.

main = do
   let loop 0 = return ()
       loop v = do
          putStrLn "x not yet 0, enter an adjustment"
          a <- readLn
          loop (v+a)
   loop 23
   putStrLn "x reached 0! Exiting"

Не элегантный код с любой натяжкой, но, по крайней мере, «защита в то время» теперь не делает ненужного ввода-вывода.

Обычно программисты на Haskell изо всех сил стараются отделить чистые вычисления от операций ввода-вывода, насколько это возможно. Это потому, что это часто приводит к лучшему, более простому и менее подверженному ошибкам коду.

person chi    schedule 13.02.2017