foo:: Int -> Int -> Int
foo z x = if (z < 100)
then z * foo (z+(x*z)) z
else z
Run Code Online (Sandbox Code Playgroud)
每次从它自己调用时,你如何打印出(整数z)一个输出?你能有返回IO和Int的函数吗?你需要辅助功能吗?
is7*_*s7s 19
为简单起见,您可以使用跟踪.然而,它不受欢迎的真实生产代码,因为它打破了参考透明度.
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
Run Code Online (Sandbox Code Playgroud)
Dan*_*ner 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
Run Code Online (Sandbox Code Playgroud)
例如,您可以通过设置打印递归调用
main = fst $ foo 13 7
Run Code Online (Sandbox Code Playgroud)
或者您可以通过设置打印答案
main = print . snd $ foo 13 7
Run Code Online (Sandbox Code Playgroud)
或者其他六件事.当然,这种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
Run Code Online (Sandbox Code Playgroud)
使用它与上面的相似,但是额外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
Run Code Online (Sandbox Code Playgroud)
这种方法的优点是你可以获得一个调用值列表,而不是打印该列表的IO操作,这样你就可以用更有趣的方式来调用这些调用.
基于@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
Run Code Online (Sandbox Code Playgroud)
在这里,我们已经介绍的定义foo与trace在将计算得到一个后卫False,这样它会一直下降,通过对原始定义。这样,我们就不会干扰我们的函数,并且可以通过注释掉该行来打开或关闭跟踪。