Неявный параметр не найден в приложении функции

Если я определяю функцию печати, которая принимает только числа, как:

def print[T <% Number](value:T) {}
print: [T](value: T)(implicit evidence$1: (T) => java.lang.Number)Unit

Я могу вызвать вышеуказанное с помощью:

print(5)
print(5.5)
print(6L) 

Но не со строкой:

print("aaa")  
<console>:7: error: could not find implicit value for evidence parameter of type (java.lang.String) => java.lang.Number
       print("aaa")

Это ожидаемо.

Но если я определяю функцию печати как:

def print2[T <% Number]: T => Unit = value => { } 
print2: [T](implicit evidence$1: (T) => java.lang.Number)(T) => Unit

Обратите внимание, что неявный параметр является первым параметром, а не последним.

Если я попытаюсь вручную определить вышеуказанную функцию:

def print3[T](implicit f: (T) => java.lang.Number)(value:T):Unit =  { }  
<console>:1: error: '=' expected but '(' found.
       def print3[T](implicit f: (T) => java.lang.Number)(value:T):Unit =  { }

По сути, приведенное выше не является допустимым определением функции, но компилятор создает его, когда я ранее определил print2.

Когда я вызываю print2 с Int:

print2(5)
<console>:7: error: type mismatch;
 found   : Int(5)
 required: (?) => java.lang.Number
       print2(5)

если я его параметризую:

print2[Int](5)
<console>:7: error: type mismatch;
 found   : Int(5)
 required: (Int) => java.lang.Number
       print2[Int](5)

Похоже, он не может найти неявное преобразование из scala.Int => java.lang.Integer.

Как я могу переопределить print так, чтобы он возвращал функции, а также правильно обращался к неявным?


person ssanj    schedule 22.02.2011    source источник
comment
Вы путаете методы с функциями. Почитайте об их различиях.   -  person Daniel C. Sobral    schedule 22.02.2011
comment
Переполнение стека поиска. Я сижу на телефоне, поэтому мне сложно искать ссылки.   -  person Daniel C. Sobral    schedule 22.02.2011
comment
Я думаю, что это, вероятно, случайность реализации scalac. Если подумать, неявные параметры в любом месте, кроме конца, не имеют смысла. Допустим, это разрешено def foo(implicit i: Int)(j: Float)(implicit: k: Int)(l: Double) = .... Что именно это означает для приложения foo(1)(2)(3) ? Это неоднозначно.   -  person Y.H Wong    schedule 22.02.2011
comment
Я согласен. Имплициты должны быть последним параметром.   -  person ssanj    schedule 22.02.2011


Ответы (1)


Проблема здесь в том, что вы передаете 5 как неявный параметр.

Теперь, когда я на компьютере, несколько исправлений:

def print[T <% Number](value:T) {}

Вы называете это функцией, но это метод.

def print2[T <% Number]: T => Unit = value => { }

Опять же, вы называете это функцией. На самом деле это метод, который возвращает функцию. Метод получает один параметр типа, T, и один неявный параметр.

print2(5)

Итак, здесь вы вызываете метод print2, передавая 5 в качестве его неявного параметра. Тип T еще не выведен, потому что он сначала пытается согласовать 5 с ожидаемым типом T => Number. Однако, поскольку 5 не соответствует Function1[T, Number], он терпит неудачу, даже не выводя T.

Есть много способов вызвать print2. Например:

print2(implicitly[Int => Number])
print2[Int]
(print2: Int => Unit)
val f: Int => Unit = print2

Однако для вызова функции, возвращаемой print2, вы должны избегать того, чтобы (5) выглядело как неявный параметр метода print2. На самом деле есть только один случай выше, который требует чего-то другого:

print2(implicitly[Int => Number])(5)
print2[Int].apply(5)
(print2: Int => Unit)(5)
val f: Int => Unit = print2; f(5)

Теперь в большинстве этих примеров используются явные, а не предполагаемые параметры типа. Рассмотрим, что было бы в его отсутствие:

print2.apply(5)

Поскольку в print2 не было передано ни одного параметра, он выбирает наиболее конкретный тип, который соответствует границам T. Поскольку T не имеет границ, выбирается Nothing. Затем он пытается найти неявный Nothing => Unit. Поскольку такого неявного нет, он терпит неудачу.

Параметр функции, который будет возвращен print2, никогда не анализируется, чтобы помочь в выводе типа.

person Daniel C. Sobral    schedule 22.02.2011
comment
Как мне вызвать print2 так, чтобы использовался неявный параметр? - person ssanj; 22.02.2011
comment
Я могу назвать это так: print2(неявно[Int => java.lang.Number])(5). Вряд ли самое красивое решение. - person ssanj; 22.02.2011
comment
@ssanj, вы можете использовать print2[Int].apply(5), хотя я понимаю, что это вряд ли то, что вам нужно. Однако вы хотите, чтобы язык работал так, как он не работает. - person Daniel C. Sobral; 22.02.2011