2013-12-11 83 views
1

我剛剛學習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. 爲什麼我需要在真實比賽中->之後的表情?
+0

這是一個簡單的memoized版本的階乘函數。 –

回答

1

尋址的評論:

真正比賽的一個更常見的版本將是

|true,result -> result 

您需要的->後位實際上返回一個值。

在錯誤匹配,實際上你需要計算階乘,通過計算

n * factorial(n-1) 

事實上,一個更好的版本的虛假情況會

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

TryGetValue返回一個布爾值(顯然只有一個值),那麼true和false後的第二個元素是什麼(導致你的答案)?另外,爲什麼我不能在錯誤匹配中的「 - >」之後加上「factorials.Add(n,n * factorial(n-1))」? – reggaeguitar

+1

'Trygetvalue'實際上也會返回一個值 - 請參閱http://msdn.microsoft.com/en-us/library/bb347013(v=vs.110).aspx。這是你的版本需要'_'的原因。你可以擁有自己的版本,但是這樣做的遞歸調用會浪費兩次。 –

+1

'TryGetValue'有一個out參數,F#作爲第二個元素。 –

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 *階乘(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) 

功能有兩種方式結束。一個通過true,另一個通過false。所以這兩個分支都以每個分支中最後一個函數的int值結束。

n * factorial(n-1) 

2.爲什麼我還需要後表達 - >在真正的比賽?

匹配語句獲取匹配結果,例如, factorials.TryGetValue(n)並匹配可能的模式。由於此匹配的簽名是(bool * int),因此您已將所有模式與(true,)和(false,)匹配。現在對於每種匹配模式,您必須具有詳細說明要完成的代碼。 - >將代碼中的模式與詳細說明要完成的代碼分開。將匹配和模式視爲切換語句。您需要爲每個交換機選項採取一些操作。

+0

感謝您的詳細解釋。您鏈接的答案不包括memoization,這是本練習的重點。附:我來自C#的土地,這就是爲什麼我試圖學習F#和函數式編程,感謝您的建議 – reggaeguitar

+0

你在問題或標題中提到記憶的地方? –

+0

我沒有抱歉,只是編輯它。感謝您的鏈接 – reggaeguitar