2010-11-17 5 views
5

В C++ можно сделать следующее:Возможно ли кодировать типичные типы возвращаемых данных в Scala, аналогичные шаблонам C++?

template<typename T, typename V> 
struct{ 
    void operator()(T _1, V _2){ 
     _2.foo(_1); 
    } 
}; 

, который позволяет мне произвольно решили использовать любой объект, который имеет какой-то метод, называемый «Foo», которая принимает некоторый тип «Т» без указания заранее либо типа аргумента «foo» или тип возврата указанной функции.

Когда я смотрю на Scala см черты, как Function1, и я играю с определениями функций, как

def foo[T<:{def foo():Unit}](arg:T) = //something 
def bar(x:{def foo():Unit}) = //something 
def baz[T,V<:Function1[T,_]](x:T, y:V) = y(x) 

Я смотрю на себя и думаю, почему я не могу сделать то же самое? Почему «база» возвращает Any? Не удается ли вывести фактический тип возвращаемого значения во время компиляции? Почему я должен объявлять возвращаемый тип «foo», если я даже не могу его использовать?

Я хотел бы быть в состоянии сделать

def biff[T,V:{def foo(x:T):Unit}] = //something 

или

def boff[T<:{def foo(x:Double):_}](y:T) = y.foo _ 

Вы можете сделать это, и я просто что-то отсутствует? Или если нет, почему бы и нет?

+0

Я не понимаю пример 'biff'. Есть ли отсутствующий аргумент? –

+0

@Aaron Novstrup нет недостающих аргументов. Я получаю сообщение об ошибке, когда я так утверждаю. Говорит, что я не могу определить «V» так, что это зависит от «T». – wheaties

ответ

11

Update:

На самом деле, вы можете сделать гораздо лучше, и тип inferencer будет поможет вам:

def boff[T,R](y: T)(implicit e: T <:< {def foo(x: Double): R}) = e(y).foo _ 

Для baz, та же техника улучшит тип умозаключение:

def baz[T,R,V](x:T, y:V)(implicit e: V <:< (T => R)) = e(y).apply(x) 

scala> baz(1, (i: Int) => i+1) 
res0: Int = 2 

Вы можете улучшить изображение:

def baz[T,R](x: T)(f: T => R) = f(x) 

Первое решение:

Тип inferencer не будет поставлять T тип для вас, но вы можете сделать:

class Boff[T] { 
    def apply[R](y: T)(implicit e: T <:< {def foo(x: Double): R}) = e(y).foo _ 
} 
object boff { 
    def apply[T] = new Boff[T] 
} 
+0

+1 Это умно. –

2

Для foo:

def foo[R,T<:{def foo():R}](arg:T) = ... 

В случае baz вы говорите, что V должна быть функцией от T до некоторого типа. Этот тип не может отображаться в типе результата: как вы могли его написать? Поэтому компилятор может только вывести, что тип результата равен Any. Если вы даете ему имя, однако, вы получите

scala> def baz[T,R,V<:Function1[T,R]](x:T, y:V) = y(x) 
baz: [T,R,V <: (T) => R](x: T,y: V)R 
6

Принципиальное различие между Scala и C++ является то, что каждый класс в Scala компилируется один раз, а затем становится доступным, для использования с все, что зависит от него , тогда как шаблонный класс в C++ должен быть скомпилирован для каждой новой зависимости.

Итак, на самом деле шаблон C++ генерирует N скомпилированных классов, а Scala генерирует только один.

Невозможно ли вывести фактический тип возврата во время компиляции?

Потому что это необходимо решить в момент компиляции класса, который может отличаться от времени его компиляции.

+0

Спасибо, Дэниэл. Вы всегда предоставляете отличное «почему». – wheaties