Haskell中的内置阶乘函数

39

我知道这听起来像是一个愚蠢的问题,但是问题如下:Haskell 中是否有内置的阶乘函数?

谷歌给我提供了一些关于 Haskell 的教程,解释了我如何自己实现阶乘函数,并且我在 Hoogle 上也没有找到任何相关的信息。我不想每次需要使用阶乘函数时都重新编写代码。

我可以使用 product [1..n] 代替阶乘函数,但是否存在一个真正的 Int -> Int 阶乘函数呢?


嗯,在“标准预定义部分”中没有阶乘的“内置”算符... - hvr
2
很不可能。大多数需要阶乘函数(在任何编程语言中)的人都是为了完成作业/练习,而不是为了实际工作。如果确实需要这个功能,只需硬编码一个包含所有小于maxBound :: Int(2 ** 32或最多2 ** 64)的阶乘数字的数组即可更容易实现。 - user395760
10
那么前奏之外呢?我不明白为什么阶乘只能是一种练习。它是一个有用且通用的操作。 - Simon Bergot
6
笑话传送门:http://www.willamette.edu/~fruehr/haskell/evolution.html - fcar
8个回答

57
尽管阶乘函数常用于示例,但实际上并不是很有用。数字增长得非常快,大多数涉及阶乘函数的问题都可以(而且应该)以更有效的方式计算。
一个简单的例子是计算二项式系数。虽然可以将它们定义为:
choose n k = factorial n `div` (factorial k * factorial (n-k))

不使用阶乘会更加高效:

choose n 0 = 1
choose 0 k = 0
choose n k = choose (n-1) (k-1) * n `div` k 

所以,没有,在标准prelude中没有包括它。斐波那契数列、阿克曼函数或许多其他在理论上有趣但在实践中不常用的函数也没有被包含在标准库中。

话虽如此,Hackage上有许多数学库可用


7
我理解这个想法。但是,在计算时,拥有像阶乘、二项式系数等规范函数可以简化代码。我同意这种函数并非每天都需要使用,但是... - Simon Bergot
请注意,choose是Test.QuickCheck包中的内置函数,因此即使在不使用Test.QuickCheck时此示例也可以工作,但最好将其命名为choose'或完全不同的名称。 - lindhe
计算阶乘在生成排列方面非常有用。 - recursion.ninja
6
@Lindhea,Test.QuickCheck 可能是你的工作流程(以及其他人)中重要的一个包,但它并不拥有choose函数,这个函数被数学家们使用已经很久了。 - dfeuer
2
@lindhe 使用限定符进行消歧,而不是任意的名称扩展。 - Lemming

8

5
不,但你可以轻松地编写一个函数。如果你担心每次需要重写该功能,你可以将其编写为模块或库的一部分(这取决于你想要多远,以及你有多少类似的函数)。这样,你只需编写一次即可,并且在需要时可以快速引用到任何其他项目中。

谢谢。只是感觉奇怪的是,Haskell在数学库中没有这种类型的函数。 - Simon Bergot

4
fac = product . flip take [1..]

2
fac n = product [1..n] - Jacob-Jan Mosselman

4

2

您有一个名为product的函数,它在标准预定义中。结合范围,您可以轻松地获得阶乘函数。

factorial n = product [n, n-1 .. 1]
nCr n r = n' `div` r'
    where
    -- unroll just what you need and nothing more
    n' = product [n, n-1 .. n-r+1]
    r' = factorial r

2
fact n = if n == 0 then 1 else n * fact(n-1)
fact n = foldl(*) 1 [1..n]
fact n = product [1..n]

您可以选择以下任意一种方式


0
如果你正在寻找一个 lambda 表达式,那么你可以始终使用经典的 fix (\f x -> if x == 0 then 1 else x * (f (x - 1)))

15
这里有一些更加有趣的实现方式,具体请参见链接:http://www.willamette.edu/~fruehr/haskell/evolution.html。 - hammar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接