来自(SWI)Prolog我发现很难让Haskell动态提供输出。
最简单的例子,我希望Haskell在每次迭代时打印一些东西:
fac 0 = 1
fac n = fac ( n-1 ) * n
或者我想从一个永不停止的程序中获得输出......
-- A possible halt statement...
-- find_primes l 100 = l
find_primes l n = if ( is_prime l n ) then find_primes nn s else find_primes l s
where s = n + 1
nn = n:l
is_prime :: Integral a => [a] -> a -> Bool
is_prime [] n = True --print the prime number on the fly
is_prime (h:t) n = if ( r /= 0 ) then is_prime t n else False
where r = n mod h
前奏> find_primes [] 2
答案 0 :(得分:13)
您有三种选择:
首先:在任何地方传播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
)。用于拍摄自己的脚和调试目的。
第三:代替在代码中混合I / O和计算,懒惰地生成一个[潜在无限]数据结构,其中包含纯函数中的中间结果并单独使用它。例如,无穷大的阶乘列表可以写成:
facs = scanl (*) 1 [1..]
并按如下方式使用,以产生与上述示例中调用fac 10
相同的结果:
forM_ (take 11 $ zip [0..] facs) $ \(i, x) ->
putStrLn $ show i ++ "! = " ++ show x
答案 1 :(得分:2)
还有一些选项,rkhayrov没有cover in their answer
如果您只想要调试信息,请考虑使用Debug.Trace
's trace
function。
import Debug.Trace
fact :: (Ord a, Num a) => a -> a
fact n | n > 1 = traceShow n $ n * fact (n-1)
| otherwise = traceShow n $ 1
但是,我不建议使用它而不仅仅是寻找bug。绝对不应该进入生产代码。
如果您想在工作时记录信息,请考虑使用Writer Monad。
import Control.Monad.Writer.Lazy
import Control.Applicative ((<$>))
fact :: (Ord a, Num a) => a -> Writer [String] a
fact n = do
tell $ [show n]
if n > 1
then
(n*) <$> fact (n-1)
else
return 1
您也可以更通用,并使用MonadWriter
类型类。