2016-09-21 2 views
2

Может кто-нибудь объяснить мне, почему тип r1: (String => String, String), но тип r2 - String => (String, String)? Спасибо.scala - тип кортежа с частичной прикладной функцией

def f1(n: String, m: String): String = m + n 
val f2: String => String = f1(_, "something") 
val r1: (String => String, String) = f2 -> "foo" 
val r2: String => (String, String) = f1(_, "something") -> "foo" 

ответ

0

Некоторые вещи меня смущали даже после прочтения ответа Джатина. Вот мои выводы после некоторых дальнейших исследований. Обратите внимание: чтобы сохранить ввод текста, я не использую титры с левой стороны и пусть материал Scala infer.

def f1(n: String, m: String): String = m + n 

// f1: (n: String, m: String)String 

val f2 = f1(_, "something") 

Как правило, подчеркивания в выражении представляют собой анонимные функции, которые соответствующим образом расширяются компилятором. Если компилятор не может найти подходящий тип для «подчеркивания» параметра, он будет жаловаться, как показано ниже:

// <console>:12: error: missing parameter type for expanded function ((x$1) => f1(x$1, "something"))  

val f2 = f1(_:String, "something") // Specifiying the type of the `_` as `_:String` fixes the missing parameter type error above. 

// f2: String => String = <function1> 

val r1 = f2 -> "foo" 
// r1: (String => String, String) = (<function1>,foo) 

Теперь важные вещи. Почему нижняя строка не дает тот же результат, что и r1 выше! Причина кроется в отличном ответе Даниилом в underscore scoping rules.

val r2 = f1(_:String, "something") -> "foo" 
// r2: String => (String, String) = <function1> 

В соответствии с 1-го правила в ответ Даниилом, объем анонимной функции будет включать в себя всю правую часть выражения в . Так расширенная анонимная функция выше будет

(x:String) => f1(x:String, "something") -> "foo" 

Что дает функцию подписи: String => (String, String)

Для того, чтобы исправить это, мы используем 2-ое правило в ответ Собрал и ограничить объем анонимной функции, связанной с _, заключив f1 выражение с() или {}, как показано ниже:

val r3 = (f1(_:String, "something")) -> "foo" 
r3: (String => String, String) = (<function1>,foo) 

Теперь, мы получаем тот же результат, как val r1 = f2 -> "foo"

+0

Спасибо. Теперь это имеет смысл. – limuhob

3

Давайте посмотрим, что происходит в place holder синтаксис для анонимных функций:

val f2: String => String = f1(_, "something") 

Он вспененных как: (x$1: String) => f1(x$1, "something")" (Начните Repl с scala -Xprint:typer)

С f2 -> "foo", он просто становится (f2,"foo") и следовательно (String => String, String)

С f1(_, "something") -> "foo", она оценивается как:

(x:String) => f1(x,"something") -> foo 
(x:String) => (f1(x,"something") , foo) 
(String => (String, String)) 

Если путаница почему заполнитель оценивается в первую очередь?

Оценка места и дерево отрегулировано во время компиляции. Где, как и в случае с ->, он оценивается во время выполнения как кортеж a из-за неявным.

+0

Хммм спасибо! – limuhob

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