2017-02-09 86 views
4

Я новичок в scala и проходил курс coursera для функционального развития scala. Ниже приведен фрагмент кода объясняет о выделкеПример scara currying

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 принимает 2 аргумента (одна функция и other - значение для x), но когда он вызывается из fixedPoint, мы не передаем значение x. Поэтому я предположил, что он создает частичную функцию, которая отправляется обратно в sqrt, где значение x передается из sqrt (x: Double) agrument. Так что я сделал следующую функцию, которая не может скомпилировать

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, подробнее [здесь] (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) 

Если вы хотите создать выделанной функцию, где один не ожидается Scala делает вас добавить _ или (_)(_), чтобы подтвердить свое намерение:

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

Другой способ избежать его в этом случае должен был бы указать тип возвращаемого значения для noIdea:

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

_ - это просто способ убедиться, что вы действительно хотите создать функцию и не забудьте передать дополнительный аргумент.

 Смежные вопросы

  • Нет связанных вопросов^_^