2016-06-23 6 views
1

В чем разница между этими двумя кодовыми блоками?Currying in Scala: несколько параметров в функции, включая анонимную функцию типа (=> A)

def measure[A](histogram: Histogram)(thunk: ⇒ A): A = { 
    val start = RelativeNanoTimestamp.now 
    try thunk finally { 
    val latency = NanoInterval.since(start).nanos 
    histogram.record(latency) 
} 

def measure[A](histogram: Histogram, thunk: ⇒ A): A = { 
    val start = RelativeNanoTimestamp.now 
    try thunk finally { 
    val latency = NanoInterval.since(start).nanos 
    histogram.record(latency) 
} 

Github Source

+2

В 1-м, два аргумента кэрри, во 2-ом они не являются. Что вы пытаетесь изучить/решить? – jwvh

+0

@jwvh Что польза от каррирования против альтернативы? Спасибо за ответ! – Shehaaz

+0

@jwvh Я вижу, что вы можете частично вызвать функцию с currying. http://docs.scala-lang.org/tutorials/tour/currying.html – Shehaaz

ответ

3

=> A является ленивым параметром. Он будет оцениваться при упоминании в функции. Это может быть функция, производящая значение или просто значение.

Основное различие между одним и несколькими списками параметров, как в вашем примере:

def measure[A](histogram: Histogram)(thunk: ⇒ A) 
def measure[A](histogram: Histogram, thunk: ⇒ A) 

(не учитывая implicits и умозаключений типа), как вы применить функцию:

scala> def f[A](i: Int)(p: => A): A = { p } 
f: [A](i: Int)(p: => A)A 

scala> f(1)(2) 
res0: Int = 2 

scala> f(1){ println("something") } 
something 

scala> f(1){ 
    | println("test") 
    | } 
test 

scala> def f2[A](i: Int, p: => A): A = { p } 
f2: [A](i: Int, p: => A)A 

scala> f2(1, 2) 
res4: Int = 2 

scala> f2(1, println("test")) 
test 

scala> f2(1, { println("test") }) 
test 

Смотри, что f с несколькими списками параметров позволяет нам писать в этом стиле: f(...){...}, а f2 - немного менее изящный, если у вас есть многострочный код в качестве второго аргумента: f(..., {...}).

Кроме того, если вы делаете много в карирования/частичного применения затем f2 немного легче иметь дело с чем f:

scala> val f_withFirstArg = f(1) _ 
f_withFirstArg: (=> Nothing) => Nothing = <function1> 

scala> val f2_withFirstArg = f2(1, _) 
<console>:8: error: missing parameter type for expanded function ((x$1) => f2(1, x$1)) 
     val f2_withFirstArg = f2(1, _) 
           ^

Мы должны указать параметр типа явно, определение типа не может коротко:

scala> val f2_withFirstArg = f2(1, _: String) 
f2_withFirstArg: String => String = <function1> 

Если вы хотите получить техническую информацию об этом, то стоит отметить, что они фактически имеют другой тип:

scala> :type f _ 
Int => ((=> Nothing) => Nothing) 

scala> :type f2 _ 
(Int, => Nothing) => Nothing 

f - это функция, которая принимает Int и возвращает другую функцию, которая принимает тип A и будет производить тип A. f2 - это функция, которая принимает 2 аргумента: Int и A и возвращает A.

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

Наконец, вы всегда можете конвертировать из одного типа функции к другой до тех пор, как это имеет смысл:

scala> f2 _ 
res13: (Int, => Nothing) => Nothing = <function2> 

scala> f2 _ curried 
warning: there were 1 feature warning(s); re-run with -feature for details 
res14: Int => ((=> Nothing) => Nothing) = <function1> 

scala> f _ curried 
<console>:9: error: value curried is not a member of Int => ((=> Nothing) => Nothing) 
       f _ curried 
       ^

scala> f _ tupled 
<console>:9: error: value tupled is not a member of Int => ((=> Nothing) => Nothing) 
       f _ tupled 
       ^

scala> f2 _ tupled 
warning: there were 1 feature warning(s); re-run with -feature for details 
res17: ((Int, => Nothing)) => Nothing = <function1> 

Обратите внимание, что мы не можем сделать f выделанной, потому что уже есть. Мы не можем сделать f, потому что это ничего не изменит. Тем не менее, мы можем преобразовать f2 в f с помощью curried:

scala> :type f _ 
Int => ((=> Nothing) => Nothing) 

scala> :type f2 _ curried _ 
Int => ((=> Nothing) => Nothing) 
+0

Благодарим вас за подробное объяснение! Это, наконец, работает! https://gist.github.com/shehaaz/7ea265d8b43006d7b395a035c3479925 – Shehaaz