2013-11-04 98 views
2

我目前正在通過Martin Odersky的Coursera類,Scala中的函數式編程原則的視頻講座。在講義2.1中,他使用基本函數sum()演示了高階函數的組成。他在沒有尾遞歸的情況下實現了階乘,但是我嘗試了尾遞歸,因爲它仍然只是一行代碼。因此,我認爲Odersky沒有這種類型的不匹配。在定義sum()時,參數f需要Int並返回Int。我知道我可以通過調整我的函數來解決這個問題,但是這讓我想到如何設計更高階的函數。 有沒有一種方法可以調整或繞過此類型定義,以便允許採用靈活數量參數的函數?有人向我展示了一次Haskell,我想知道Scala的函數參數是否可以類似鬆散的方式輸入......或者也許有更多原生Scala的解決方案。請假設我昨天剛剛開始和Scala一起玩,並且在你的解釋中對計算機科學知識有限,因爲情況正是如此。更高階函數中的類型定義和類型不匹配

def sum(f: Int => Int, a: Int, b: Int): Int = 
    if (a > b) 0 else f(a) + sum(f, a+1, b) 


//Factorial with tail recursion. The one in the lesson DOES NOT use tail recursion. 
//prev is an accumulator. 
def fact(a: Int, prev:Int = 1): Int = 
     if (a == 0) prev else fact(a-1, a * prev) 


def sumFactorials(a: Int, b: Int): Int = sum(fact, a, b) 

*我知道,我可能只是通過另一個函數嵌套在我目前的fact()解決這個問題,比如:

def factorial(a: Int): Int ={ 
    def fact(n: Int, prev:Int = 1): Int = 
      if (n == 0) prev else fact(n-1, n * prev) 
    fact(a) 
} 

我從我前面提到的Haskell經驗的印象是函數式編程促進功能只服用一個論點允許currying。無論如何,這與實際問題有點相似,但如果我只是用我的問題的精神屠殺FP,可以隨時在評論中解決這個問題。

回答

2

我認爲這裏有一些事情正在進行。

首先,我想你正在試圖用事實函數(使用具有默認值的函數,好像它的類型實際上只有一個參數)是不可能的。即使第二個Int默認爲1,Int(Int,Int)=> Int仍然是(Int,Int)=> Int。不能將它作爲Int => Int傳遞。儘管如此,我可以看到你可能會認爲自己可以在哪裏。

其次,你的事實和因子函數是不等價的。無論您遞歸多少次,階乘函數都會反覆使用原始值「a」。事實函數在每次調用中使用遞減的'a'。

根據您的「固定」因子函數,該函數有效地採用三個參數:原始a,遞減n和乘法prev。下面的代碼是等效的。

def sum(f: (Int,Int,Int) => Int, a: Int, b: Int): Int = 
    if (a > b) 0 else f(a,a,1) + sum(f, a+1, b) 

def fact(a: Int, n: Int, prev:Int): Int = 
    if (n == 0) prev else fact(a, n-1, a * prev) 

def sumFactorials(a: Int, b: Int): Int = sum(fact, a, b) 

你也可以不寫金額爲:

def sum(f: (Int, Int) => Int, a: Int, b: Int): Int = 
    if (a > b) 0 else f(a) + sum(f, a+1, b) 

中函數f通過可能有一個默認的參數,它可能沒有,所以它不會是安全的編譯器允許f(a)呼叫。

我認爲默認參數更像是「語法糖」,就像他們說的那樣,附加到實際函數而不是像函數currying。你可以用currying來做到這一點,但你必須明確地聲明curried函數。假設你要使用的邏輯與事實(而不是階乘),你可以做到這一點,像這樣:

def sum(f: Int => Int, a: Int, b: Int): Int = 
    if (a > b) 0 else f(a) + sum(f, a+1, b) 

def fact(prev:Int = 1)(a: Int): Int = 
     if (a == 0) prev else fact(a * prev)(a-1) 

def sumFactorials(a: Int, b: Int): Int = sum(fact(1), a, b) 

請注意,我們必須交換的事實的參數的位置。

+0

謝謝馬特。 1)「固定」問題是在重寫帖子中的代碼時發生的印刷錯誤。 'a * prev'應該讀取'n * prev'。我已經更新了原文,以反映這一點。 2)你的「第一」比較重要:我認爲我不能強迫編譯器將這些匹配起來。我更具體地說,是想知道Scala是否有類似於Haskell的'也許'的東西,我可以在類型定義中使用它來表明_might_是第二個參數。 – eenblam