Haskell在递归时打印?

时间:2012-03-24 03:15:15

标签: haskell recursion

foo:: Int -> Int -> Int
foo z x = if (z < 100) 
             then z * foo (z+(x*z)) z
             else z

每次从它自己调用时,你会如何打印出(整数z)一个输出?你能有返回IO和Int的函数吗?你需要辅助功能吗?

4 个答案:

答案 0 :(得分:19)

为简单起见,您可以使用trace。然而,它不受欢迎的真实生产代码,因为它打破了参考透明度。 trace需要String打印并返回值。

import Debug.Trace

foo:: Int -> Int -> Int
foo z x = trace ("z = " ++ show z) $ if (z < 100) 
    then z * foo (z+(x*z)) z
    else z

*Main> foo 1 2
 z = 1
 z = 3
 z = 6
 z = 24
 z = 168
 72576

答案 1 :(得分:10)

为了完整起见,我将回答这个问题:

  

你能有返回IO和Int的函数吗?

......非常字面。答案是“是的!”......它有时甚至是有用的。可能这不是你想要做的初学者,但如果是,这是一个样本。

foo :: Int -> Int -> (IO (), Int)
foo z x = if z < 100 then (print z >> io, z * rec) else (return (), z) where
    (io, rec) = foo (z+x*z) z

例如,您可以通过设置

来打印递归调用
main = fst $ foo 13 7

或者您可以通过设置

来打印答案
main = print . snd $ foo 13 7

或其他六件事。当然,IO ()类型有点难以检查;你可能会考虑写这样的东西:

foo' :: Int -> Int -> Writer [Int] Int
foo' z x = if z < 100
    then tell [z] >> fmap (z*) (foo' (z+x*z) z)
    else return z

使用它与上面非常类似,但引入了额外的runWriter;例如,你可以写下这两个中的任何一个:

main = print . snd . runWriter $ foo' 13 7 -- to print a list of the calling values
main = print . fst . runWriter $ foo' 13 7 -- to print the result

这种方法的优点是你可以获得一个调用值列表,而不是打印该列表的IO操作,这样你就可以用更有趣的方式来调用这些调用。

答案 2 :(得分:4)

执行I / O的任何函数都必须在IO monad:

中返回其结果
 foo :: Int -> Int -> IO Int
 foo z x = print z >> if z < 100 then fmap (z*) (foo (z + x * z) z) else return z

请注意,if表达式的两个分支现在也必须位于IO

这与返回&{34; IOInt&#34;不同。 IO Int是表示I / O操作的值的类型,在执行时,将产生Int作为其结果(可能在执行一些I / O之后)。因此,foo的上述定义需要IntInt,并返回最终会产生Int的I / O操作。

答案 3 :(得分:3)

在@ is7s的答案的基础上,使用Debug.Trace的一个有用的习惯是这样做:

import Debug.Trace

foo:: Int -> Int -> Int
foo z x | trace ("z = " ++ show z) False = undefined
foo z x = if (z < 100) 
    then z * foo (z+(x*z)) z
    else z

在这里,我们在保护中引入了foo的{​​{1}}定义,其中trace的评估结果为False,因此它将始终落在原始定义中。通过这种方式,我们不会扰乱我们的功能,并且可以通过注释掉线来打开或关闭跟踪。