2017-02-09 100 views
4

我是scala的新手,正在進行scala功能開發課程。下面的代碼片段解釋了有關討好斯卡拉咖喱例

import math.abs 

object exercise{ 
    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 averageDamp(f: Double => Double)(x: Double) = (x + f(x))/2 

    def sqrt(x: Double) = fixedPoint(averageDamp(y => x/y))(1) 
} 

我無法理解的代碼的以下部分

fixedPoint(averageDamp(y => x/y))(1)

我知道averageDamp功能需要兩個參數(一個是功能和其他是x的值),但是當它從fixedPoint調用時,我們不會傳遞x的值。所以我認爲它創建了一個部分函數,​​它被髮回sqrt,其中x的值是從sqrt(x:Double)中傳遞的。所以,我提出以下函數編譯失敗

def noIdea(x: Double) = averageDamp(y => x/y)

有人可以解釋這樣對我?

回答

2

您需要提供下劃線才能觸發未應用方法上的eta expansion。方法沒有值,所以它們必須被轉換成函數對象才能分配給變量。當Scala知道未應用的方法應該被解釋爲函數對象時,eta擴展會自動觸發。在其他情況下,您需要用下劃線手動觸發擴展。

不知道你的Scala版本是什麼,但2.11.7使這非常清楚。下面是一個簡單的例子與縮放功能:

scala> def my_scaler(sc: Double)(x: Double): Double = sc*x 

my_scaler: (sc: Double)(x: Double)Double 

scala> def my_doubler = my_scaler(2d) // no eta exp 
<console>:13: error: missing argument list for method my_scaler 
Unapplied methods are only converted to functions when a function type is expected. 
You can make this conversion explicit by writing `my_scaler _` or `my_scaler(_)(_)` instead of `my_scaler`. 
     def my_doubler = my_scaler(2d) 
           ^

scala> def my_doubler = my_scaler(2d) _ // manual eta exp 
my_doubler: Double => Double 

scala> my_doubler(10d) 
res1: Double = 20.0 

scala> def my_tripler: Double => Double = my_scaler(3d) // auto eta exp 
my_tripler: Double => Double 

scala> my_tripler(10d) 
res2: Double = 30.0 
+0

感謝您的回覆。它與下劃線一起工作,但是如果你注意到我沒有把下劃線作爲 > def sqrt(x:Double)= fixedPoint(averageDamp(y => x/y))(1) 它仍然有效,是什麼樣的魔法這是??? –

+1

因爲在那種情況下它期待着一個函數,如果你給'noIdea'一個'Double => Double'的類型,情況也是如此。當Scala知道該值應該是一個函數('A => B')時,它會自動觸發所謂的eta擴展,閱讀更多[here](http://blog.jaceklaskowski.pl/2013/11 /23/how-much-one-ought-to-know-eta-expansion.html)。提供下劃線會自動觸發。 –

+0

@RockwellSydney看到我更新的答案 –

4

創建一樣,只有當您將它作爲參數傳遞給另一個函數或在功能,預計其他一些情況下工作的咖喱功能。由於fixedPoint接收功能,你可以簡單的寫:

fixedPoint(averageDamp(y => x/y))(1) 

當你想創建一個咖喱功能,其中一個預計不會斯卡拉讓你添加_(_)(_)以確認你的意圖:

def noIdea(x: Double) = averageDamp(y => x/y) _ 

在這種情況下避免它的另一種方式是指定返回類型noIdea

def noIdea(x: Double): Double => Double = averageDamp(y => x/y) 

_只是一種確保您確實想要創建函數並且不會忘記傳遞額外參數的方法。