2015-09-14 2 views
1

Метода только с параметром implicitСотроз функции ТОЛЬКО неявный параметр аргумент

scala> def test1 (implicit i:Int)= Option(i) 
test1: (implicit i: Int)Option[Int] 

В попытке преобразовать test1 в function, как показано ниже бросает следующие ошибки. Я должен упустить что-то очевидное здесь?

scala> def test2(implicit i:Int) = test1 _ 
    <console>:8: error: type mismatch; 
    found : Option[Int] 
required: ? => ? 
    def test2(implicit i:Int) = test1 _ 
+0

Итак, вы хотите сделать функцию, которая делает опцию из неявного i? Почему вы добавляете подчеркивание после вызова test1? – Haito

+0

Возможный дубликат [странное несоответствие типа при использовании доступа члена вместо экстрактора] (http://stackoverflow.com/questions/9610736/strange-type-mismatch-when-using-member-access-instead-of-extractor) –

ответ

0

При использовании неявного параметра у вас есть один в области. Как это:

object test{ 
    implicit var i = 10 
    def fun(implicit i: Int) = println(i) 
} 

test.fun 

И если вы хотите, чтобы сделать вариант isntance что-то вы должны использовать Some()

+0

Я думаю, что это больше проблема вывода типа @Haito. –

+0

Да, теперь я вижу это. – Haito

0

Потому что у вас есть неявное Int в объеме при определении test2, он применяется к test1, так что вы на самом деле конец с test1(i) _, что не имеет смысла для компилятора.

Если он скомпилировал, test2 вернет ту же функцию, что и test1, независимо от аргумента. Если это то, что вы на самом деле хотите, вы можете исправить это, будучи более явным: test1(_: Int) или { x: Int => test1(x) } вместо test1 _.

0

Здесь есть несколько различных возможных ответов в зависимости от того, чего именно вы пытаетесь достичь. Если вы имели в виду test2 как поведенческий, то метод - test1, тогда нет необходимости использовать знак подчеркивания (и действительно, вы не можете!).

def test3(implicit i: Int) = test1(i) 

Если вы имели в виду test2 быть поведенчески идентичны функция к test1, то вам необходимо сделать следующее:

val test4 = test1(_: Int) 

Обратите внимание, что я использую val вместо def здесь, потому что при использовании подчеркивания я поворачиваю test1, который изначально был методом в экземпляр класса (в частности, который расширяет Function2, т.е. функцию). Также обратите внимание, что test4 больше не имеет неявных параметров, так как это функция (и, насколько мне известно, функции не могут иметь неявные параметры), тогда как test1 был методом.

Почему вы должны сделать это, а не просто test1 _ оказывается довольно сложным ...

TLDR: Scala является finnicky о разнице между foo(_) и foo _ методы отличаются от функций, и неявные разрешение имеет более высокий приоритет по сравнению с eta-расширением

Превращение метода в функциональный объект посредством анонимной функции в Scala называется «eta-expansion». В общем eta-экспансия исходит из лямбда-исчисления и относится к превращению термина в его эквивалентную анонимную функцию (например, thing становится x => thing(x)) или на языке лямбда-исчисления, добавляя абстракцию над термином.

Обратите внимание, что без eta-расширения программирование в Scala было бы абсолютно мучительным, потому что методы не являются функциями. Поэтому они не могут быть переданы непосредственно в качестве аргументов другим методам или другим функциям. Scala пытается по возможности преобразовать методы в функции посредством eta-расширения, чтобы придать внешний вид тем, что вы можете передавать методы другим методам.

Так почему же следующее не работает?

val test5 = test1 _ // error: could not find implicit value for parameter i: Int 

Ну давайте посмотрим, что произойдет, если мы пытались test4 без сигнатуры типа.

val test6 = test1(_) // error: missing parameter type for expanded function ((x$1) => test1(x$1)) 

Ах, разные ошибки!

Это потому, что test1(_) и test1 _ - это тонко разные вещи. test1(_) частично применяет метод test1, а test1 _ - это направление для выполнения eta-расширения на test1до его полного применения.

Например,

math.pow(_) // error: not enough arguments for method pow: (x: Double, y: Double)Double. 
math.pow _ // this is fine 

Но что о случае, когда мы имеем только один аргумент? В чем разница между частичным применением и эта-расширением только одной абстракции? Не совсем так много. Один из способов его просмотра состоит в том, что eta-расширение является одним из способов реализации частичного приложения. Действительно, Scala Spec, кажется, молчит о разности между foo(_) и foo _ для метода одиночных параметров. Единственное различие, которое имеет для нас значение, состоит в том, что расширение, которое происходит в foo(_), всегда «связывается» более жестко, чем foo _, действительно, похоже, оно связывается так же, как и приложение метода.

Именно поэтому test1(_) дает нам ошибку о типах. Частичное применение обрабатывается аналогично обычным методам. Поскольку приложение нормального метода всегда должно выполняться до неявного разрешения, в противном случае мы не могли бы заменить неявное значение нашим собственным значением, частичное приложение имеет место до неявного разрешения. Так получилось, что метод Scala реализует частичное приложение через eta-расширение, и поэтому мы получаем разложение в анонимную функцию, которая затем жалуется на отсутствие типа аргумента.

Мое чтение раздела 6.26 из Scala Spec предполагает, что имеется заказ на разрешение различных преобразований. В частности, он, как представляется, перечисляет решающие импликации как идущие до eta-расширения. Действительно, для полностью прикладного eta-расширения казалось бы, что это обязательно будет иметь место, поскольку функции Scala не могут иметь неявные параметры (только его методы могут).

Таким образом, в случае test5, как говорит @Alexey, когда мы явно рассказывать Scala ЕТ-расширения test1 с test1 _, неявным разрешением имеет место первое, а затем ETA-расширение пытается занять место, которая терпит неудачу, потому после неявного разрешения Scala's typechecker понимает, что у нас есть Option не метод.

Так вот почему нам нужно test1(_) над test1 _.Анкета конечного типа test1(_: Int) необходима, потому что вывод типа Scala недостаточно прост, чтобы определить, что после eta-расширения test1 единственный возможный тип, который вы можете дать анонимной функции, совпадает с сигнатурой типа для метода. На самом деле, если бы мы дали системе типов достаточно намеков, мы можем уйти с test1(_).

val test7: Int => Option[Int] = test1(_) // this works 

val test8: Int => Option[Int] = test1 _ // this still doesn't 
Смежные вопросы