我有这个伪代码,可以计算用户给出的数字的阶乘。
Process without_title
Define i, tmp, x As Integers;
tmp<-1;
Write "Enter a number to calculate its factorial";
Read x;
For i <- 1 Until x Do
tmp<-tmp * i;
EndTo
Write tmp;
EndProcess
现在我想使用列表理解在 Haskell 中实现相同的代码
import Data.IORef
factorial::Int -> Int
factorial x = [tmp|i<-[1..x], modifyIORef tmp (*i)]
抛出错误说tmp
变量未定义
如何定义tmp
变量以便我可以使用它?
要使用像这样的可变变量实现阶乘函数,
IORef
您需要在 IO monad 中工作并使用一个newIORef
操作来创建您的IORef
,然后使用forM_
、traverse_
、 或sequence_
或类似的函数来对该 IO 操作集进行排序IORef
。它可能看起来像:或者,如果您更喜欢使用列表理解,因此它看起来更像您上面的尝试,例如:
(使用 strict
modifyIORef'
可以提供比lazy 更好的性能modifyIORef
。)然后可以这样调用:
这通常会比更直接、“纯粹”的解决方案慢,例如:
我的基准测试表明
IORef
基于 的版本比纯基于的版本慢大约两倍product
。嗯,使用变异变量是非常不符合哈斯克尔风格的。这是您需要使用
IO Ref
s 的原因之一:因为 ref 本身不会更改,并且修改其值被视为副作用。因此,如果您想手动实现阶乘,则可以使用递归来重复某个任务,并且通过将不同的值传递给参数可以视为使用修改后的值执行此迭代,因此:
但由于 Haskell 有一些更高级别的实用函数,我们可以生成一个项目列表,然后确定这些项目的乘积。