如果没有else else语句,如何在haskell中编写递归因子函数

时间:2017-09-19 03:19:24

标签: haskell lambda-calculus

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演算的事情。

3 个答案:

答案 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的类型不是可以接受IntInteger的函数之一!)笑话在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