Можно ли кодировать универсальные типы возвращаемых данных в Scala, похожие на шаблоны C ++? - PullRequest
5 голосов
/ 17 ноября 2010

В C ++ я могу сделать следующее:

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

, что позволяет мне произвольно решить использовать любой объект, у которого есть некоторый метод с именем "foo", который принимает некоторый тип "T", без предварительного указания либотип аргумента функции "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 _

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

Ответы [ 3 ]

11 голосов
/ 17 ноября 2010

Обновление:

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

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)

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

Вывод типа не будет предоставлять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]
}
6 голосов
/ 17 ноября 2010

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

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

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

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

2 голосов
/ 17 ноября 2010

Для 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
...