我正在通過優秀的馬丁奧德斯基的FP課程講課,其中一個講座通過牛頓的方法來演示高階函數,以找出某些函數的固定點。在我認爲類型簽名被侵犯的講座中有一個迫切的步驟,所以我會要求解釋。 (道歉長介紹這是入站 - 它認爲這是必要的。)實現這樣的算法是這樣給出scala在函數簽名中是否會破壞類型?
方式一:
val tolerance = 0.0001
def isCloseEnough(x: Double, y: Double) = abs((x - y)/x)/x < tolerance
def fixedPoint(f: Double => Double)(firstGuess: Double) = {
def iterate(guess: Double): Double = {
val next = f(guess)
if (isCloseEnough(guess, next)) next
else iterate(next)
}
iterate(firstGuess)
}
接下來,我們試着計算通過定點平方根功能,而是通過
def sqrt(x: Double) = fixedPoint(y => x/y)(1)
幼稚嘗試挫敗,因爲這樣的方法振盪(所以,對於sqrt(2)
,結果將無限期地1.0和2.0之間交替)。
爲了解決這個問題,我們引入平均阻尼,所以基本上我們計算兩個最接近計算值的均值和收斂到解決方案,因此
def sqrt(x: Double) = fixedPoint(y => (y + x/y)/2)(1)
最後,我們介紹averageDamp
功能和任務是用fixedPoint
和averageDamp
寫sqrt
。該averageDamp
定義如下:
def averageDamp(f: Double => Double)(x: Double) = (x + f(x))/2
這裏來了,我不明白的部分 - 我最初的解決方案是這樣的:
def sqrt(x: Double) = fixedPoint(z => averageDamp(y => x/y)(z))(1)
但教授。 Odersky的解決方案更簡潔:
def sqrt(x: Double) = fixedPoint(averageDamp(y => x/y))(1)
我的問題是 - 爲什麼它的工作?根據函數簽名,fixedPoint
函數應該採用函數(Double => Double
),但它並不介意傳遞一個普通的Double(這就是averageDamp
返回的值 - 事實上,如果試圖顯式指定返回類型Double averageDamp
,編譯器不會拋出錯誤)。
我認爲我的方法正確地遵循類型 - 所以我在這裏錯過了什麼?它在哪裏指定或暗示(?)averageDamp
返回一個函數,特別是在右邊明顯返回一個標量的情況下?你怎麼能把一個標量傳遞給一個明確期望函數的函數呢?你如何推理似乎不符合類型簽名的代碼?
這個鏈接應該有所幫助http://www.codecommit.com/blog/scala/function-currying-in-scala – 2014-10-09 05:29:25
嗯,那個線程已經超過我的腦袋,但另一個鏈接有點幫助。所以,我理解它的方式(如果我錯了,請糾正我)是因爲currying基本上是一個延遲函數調用 - 推遲到所有f-args被滿足(關閉)爲止。在他們之前,部分應用的f返回結果爲_another_ f(稱爲'f''),使得所有不滿意的參數形成'f''的**左手**側,而身體形成右手'f''的一側並沒有改變。我仍然無法理解引擎蓋下發生了什麼 - 誰將標量arg'x'傳遞給'averageDamp'?什麼時候? – quantum 2014-10-10 03:21:05
我認爲你掌握了柯里裏的一般想法。 'fixPoint'將'x'部分應用於'averageDamp',就在'val next = f(guess)' – 2014-10-10 11:14:00