Recursion F#中带记忆的递归阶乘函数
我只是在学习F#,我拼凑了这个函数,但我不完全明白到底发生了什么,有人能解释一下吗Recursion F#中带记忆的递归阶乘函数,recursion,f#,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
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
open System.Collections.Generic
设阶乘=字典()
阶乘.加(1,1)
设rec阶乘n=
如果n*阶乘(n-1)
|错误,->
阶乘.加(n,n*阶乘(n-1))
n*阶乘(n-1)
设a=阶乘9
我的问题是:
n*factorial(n-1)
->
后面需要一个表达式针对评论: 真正匹配的更常见版本是
|true,result -> result
您需要->
后面的位来实际返回值
在假匹配中,您需要通过计算
n * factorial(n-1)
事实上,更好的说法应该是
|false, _ ->
let r = n * factorial(n-1)
factorials.Add(n,r)
r
函数有两种结束方式。一个是真的,一个是假的。因此,这两个分支都以每个分支中最后一个函数的int退出
i、 e
2.为什么我需要在真正匹配中的->之后使用表达式
match语句获取匹配的结果,例如,
factorials.TryGetValue(n)
,并对可能的模式进行匹配。因为这个匹配的签名是(bool*int),所以您已经用(true)和(false)匹配了所有模式。现在,对于每个匹配模式,您必须有详细说明要执行的操作的代码。->将模式与详细说明要执行操作的代码分离。将匹配和模式视为switch语句。每个开关选项都需要执行一些操作。这是阶乘函数的简单记忆版本。TryGetValue返回布尔值(显然只有一个值),那么true和false之后的第二个元素是什么(答案中的结果)?另外,为什么我不能在假匹配中的“->”后面加上“factorials.Add(n,n*factorial(n-1))?Trygetvalue
实际上也返回一个值-参见这里。这就是您的版本需要的原因。您可以使用您的版本,但这会进行两次递归调用,这是一种浪费。TryGetValue
有一个out参数,F#作为第二个元素获取。感谢您的详细解释。您链接到的答案不包括记忆,这是本练习的重点。另外,我来自C#land,这就是为什么我要学习F#和函数编程,谢谢你的建议。你在问题或标题中提到记忆了吗?你会如何写一个带记忆的阶乘函数?函数不必返回max input的值,最好是返回字典(或类似的数据结构),其中包含输入的阶乘?
// 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
match factorials.TryGetValue(n) with
| true, _ -> n * factorial(n-1)
| false, _ ->
factorials.Add(n, n * factorial(n-1))
n * factorial(n-1)
n * factorial(n-1)