具有记忆的F#中的递归因子函数

时间:2013-12-11 23:46:58

标签: recursion f#

我只是在学习F#而且我把这个功能合并在一起,但是我不完全理解发生了什么,有人可以解释一下吗?

open System.Collections.Generic

let factorials = Dictionary<int, int>()
factorials.Add(1, 1)

let rec factorial n =
    if n <= 1 then 1
    else
        match factorials.TryGetValue(n) with
        | true, _  -> n * factorial(n-1)
        | false, _ -> 
            factorials.Add(n, n * factorial(n-1))
            n * factorial(n-1)     

let a = factorial 9

我的问题是:

  1. 为什么我需要在错误匹配结束时拨打n * factorial (n-1)
  2. 为什么我需要在真正匹配中的->之后使用表达式?

2 个答案:

答案 0 :(得分:1)

发表评论:

真正匹配的更常见版本是

|true,result -> result 

你需要->之后的位来实际返回一个值。

在错误匹配中,您需要通过计算

来实际计算阶乘
n * factorial(n-1)

事实上,错误案例的更好版本将是

 |false, _ -> 
     let r = n * factorial(n-1)
     factorials.Add(n,r)
     r

答案 1 :(得分:1)

// Access the library containing the Dictionary module
open System.Collections.Generic

// Crate a key value,pair named factorials, e.g. table, to hold the
// the factorial number n and it's result.
let factorials = Dictionary<int, int>()

// Add an initial entry into the factorials table for the 
// value for one and the result of the factorial of one, being one.
factorials.Add(1, 1)

// Define a recursive function for factorial
// taking one integer parameter
let rec factorial n =
    // If the parameter is less than or equal to one
    // then return one
    if n <= 1 then 1
    // If the parameter is greater than one then
    else
        // look up the result of the factorial in the factorials table.
        // Use TryGetValue when looking up value to avoid errors when
        // there is no matching key for the value.
        // There is a problem here with the way TryGetValue is used.
        // It should be used as
        //   let mutable factresult
        //   factorials.TryGetValue(n,factresult)
        // The problem causes the result of TryGetValue(n) to be
        // the tuple (bool * int) instead of bool with the 
        // value part updating the mutable factresult.
        // Next the patterns for the match are true,_ and false, _ 
        // which match the tuple of the TryGetValue(n)
        // but the _ means to toss out the value it matches
        // because it doesn't have a name, 
        // so the whole use of the factorials table is not needed.
        match factorials.TryGetValue(n) with
        // If there is an entry in the factorials table then take this action.
        // Take n and multiply it by the factorial of n-1.
        // As an example for 5 this becomes 5 * 4 * 3 * 2 * 1
        // Take the result of n * factorial(n-1) and push it on to the stack
        // as the result of the function. 
        | true, _  -> n * factorial(n-1)
        // If there is no entry in the factorials table then
        // calculate the result of the factorial of n, i.e. n * factorial(n-1))
        // and add it to the factorials table.
        // Take the result of n * factorial(n-1) and push it on to the stack
        // as the result of the function. 
        | false, _ -> 
            factorials.Add(n, n * factorial(n-1))
            n * factorial(n-1)     

let a = factorial 9

更好solution

修改

  

1.为什么我需要在错误匹配结束时调用n * factorial(n-1)?

我认为你来自一个命令性的背景,很可能是C#,因为你使用了词典。功能代码不是命令式代码。在用函数式语言编码时,必须考虑函数。函数以将结果放在堆栈上结束,除了异常之外,所有退出函数的方法都必须以相同的类型签名结束

所以对于这个匹配函数

   match factorials.TryGetValue(n) with
    | true, _  -> n * factorial(n-1)
    | false, _ -> 
        factorials.Add(n, n * factorial(n-1))
        n * factorial(n-1)

该功能有两种结束方式。一个通过真实,一个通过虚假。因此,这两个分支都以每个分支中最后一个函数的int退出。

即。

n * factorial(n-1)
  

2.为什么在 - &gt;之后我需要一个表达式?在真正的比赛中?

匹配语句获取匹配结果,例如factorials.TryGetValue(n)并匹配可能的模式。由于此匹配的签名是(bool * int),因此您已将所有模式与(true,)和(false,)匹配。现在,对于每个匹配模式,您必须具有详细说明要执行的操作的代码。 - &gt;将模式与详细说明要执行的代码分开。将匹配和模式视为switch语句。您需要为每个开关选项执行一些操作。

相关问题