У вас есть три варианта:
Первый: распространить повсюду IO
и писать на Haskell, как на необычном императивном языке.
fac 0 = putStrLn "0! = 1" >> return 1
fac n = do
x <- fac (n - 1)
let r = x * n
putStrLn $ show n ++ "! = " ++ show r
return r
Второй: использовать unsafePerformIO
и его производныенапример Debug.Trace
).Полезно для стрельбы в ноги и в целях отладки.
В-третьих: вместо того, чтобы смешивать ввод / вывод и вычисления в коде, лениво генерировать [потенциально бесконечную] структуру данных, содержащую промежуточные результаты в чистой функции, и использовать еепо отдельности.Например, бесконечный список факториалов можно записать в виде:
facs = scanl (*) 1 [1..]
и использовать следующим образом, чтобы получить тот же результат, что и при вызове fac 10
в приведенном выше примере:
forM_ (take 11 $ zip [0..] facs) $ \(i, x) ->
putStrLn $ show i ++ "! = " ++ show x