fac n = if n < 2 then 1 else n * fac (n-1)
main = do
putStrLn "Enter a number: "
number <- getLine
print $ number >>= fac
我不知道如何在没有if语句的情况下编写递归因子函数。我们的教授说有关lambda演算的事情。
答案 0 :(得分:5)
模式匹配和防护是两种特别简单的方法。防御本质上是if-then-else的另一种语法;它们看起来像这样:
fac n | n < 2 = 1
| otherwise = n * fac (n-1)
与if-then-else不同,它们干净地支持多种条件;例如,还可以编写
fac n | n < 0 = error "nah"
| n == 0 = 1
| n == 1 = 1
| n > 1 = n * fac (n-1)
在if-then-else形式下看起来不那么漂亮。
通过模式匹配,通常可以编写多个定义方程式:
fac 0 = 1
fac 1 = 1
fac n = n * fac (n-1)
特别是对于数字,这也基本上是一个if-then-else;但对于编译器集成较少的数据类型,通常无法使用if-then-else进行模拟,并且通常会产生非常自然的代码。
另一种非常好的方法是将递归推送到现有的Prelude函数中;在实践中你可以发现越多的迭代模式,你可以通过不重复实现相同的循环来避免更多的错误。对于这个,您可以使用product
和特殊的枚举语法:
fac n = product [1..n]
更先进(也更糟糕)的技术是定义一种新的数字;例如教会数字允许数字的生产者驱动递归,而消费者(这里,fac
)只提供基本情况。在这种风格中,您可能会看到如下内容:
fac n = fst (n (1,1) (\(prod, sum) -> (prod*sum, sum+1)))
(但请注意,这需要一种非常特殊的数字 - 当然fac
的类型不是可以接受Int
或Integer
的函数之一!)笑话在The Evolution of a Haskell Programmer中得出了合乎逻辑且令人恐怖的结论。
答案 1 :(得分:2)
试试这个:
factorial 0 = 1
factorial n = n * factorial (n - 1)
使用尾递归:
factorial n = f n 1
f 0 acc = acc
f n acc = f (n-1) (acc*n)
main = print $ factorial 5
输出:
120
答案 2 :(得分:1)
if / then / else和guards实际上只是模式匹配的语法糖。
if b
then c
else d
desugars to
case b of
True -> c
False -> d
类似地,
f x
| b = c
| d = e
f x = g
desugars to
f x = case b of
True -> c
False -> case d of
True -> e
False = g
因此,您可以直接使用case
。但是,您可以手动执行相当简单的优化。如果你看到
case x == p of
True -> a
False -> b
其中p
由构造函数和文字构成,您可以用
case x of
p -> a
_ -> b