2013-03-07 10 views
15

Czy istnieje składnia pozwalająca na generyczne parametry typu w literałach funkcjonalnych? Wiem, że mogę zawinąć go w sposób taki jak:W programie Scala można używać ogólnych parametrów typów z definicjami * funkcji *?

def createLongStringFunction[T](): (T) => Boolean = { 
    (obj: T) => obj.toString.length > 7 
} 

ale potem skończyć konieczności wywołania metody dla każdego typu T i uzyskanie nowej funkcji. Spojrzałem przez odniesienie języka, a jednocześnie widzę, że składnia dosłowne funkcja jest tłumaczony przez kompilator do instancji Functionn obiektu, który sam ma ogólne typy danych wejściowych, wygląda na to magiczne kompilator realizuje te parametry w czasie kreacja. Nie znalazłem żadnej składni, która pozwoli mi w efekcie "pozostawić jeden lub więcej parametrów typu" niezwiązane ". Co wolałbym coś wzdłuż linii:

// doesn't compile 
val longStringFunction: [T](T) => Boolean = (obj: T) => obj.toString.length > 7 

Czy coś takiego istnieje? Lub, jeśli o to chodzi, jaki jest wyraźny typ funkcji rozszerzania eta, gdy rozszerzana metoda ma parametry ogólne?

Jest to jedynie przykład wymyślony bezużyteczny. Oczywiście mógłbym tylko użyć funkcji Any tutaj.

Odpowiedz

18

Nie, parametry typu stosuje się wyłącznie do metod i nie funkcjonują obiekty. Na przykład,

def f[T](x: T) = x  //> f: [T](x: T)T 
val g = f _   //> g: Nothing => Nothing = <function1> 
// g(2)    // error 
val h: Int=>Int = f _ //> h : Int => Int = <function2> 
h(2)     //> res0: Int = 2 

Sposób f nie może być przekształcony w polimorficznej obiektu funkcji g. Jak widać, wywnioskowany typ g jest w rzeczywistości Function1[Nothing, Nothing], który jest bezużyteczny. Jednak z podpowiedzi typu możemy skonstruować h: Function1[Int,Int], który działa zgodnie z oczekiwaniami dla argumentu Int.

+0

Dzięki, bałam się, że może być inaczej. Rozszerzenie metody w ten sposób otwiera jednak drzwi dla bardziej złożonych przypadków. Chociaż nie mogę znaleźć sposobu, aby to zrobić bez pośredniej metody, wskazówka typu przydziału może nieść to zadziwiająco daleko, na przykład: 'def doStuff [T, U] (moreStuff: T => U) (obj: T) = moreStuff (obj) czas valAndAHalf = doStuff [Int, Double] (_ * 1.5) _' , który jest dość mocno zasymilowany od jego jawnego odpowiednika 'def doStuff [T, U] (moreStuff: T => U) (obj: T): U = moreStuff (obj) val timeAndAHalf: Int => Double = (num: Int) => doStuff [Int, Double] (num => num * 1.5) (num) ' – erich2k8

+4

Co jest powodem, że parametry typu nie mają zastosowania do obiektów funkcyjnych? –

1

Ponieważ longStringFunction zdefiniowane następująco jest wartością , które muszą mieć pewne danego typu.

val longStringFunction: (T) => Boolean = (obj: T) => obj.toString.length > 7 

Jednakże, można ponownie użyć funkcji obiektu z metody:

scala> val funObj: Any => Boolean = _.toString.size > 7 
funObj: Any => Boolean = <function1> 

scala> def typedFunction[T]: T => Boolean = funObj 
typedFunction: [T]=> T => Boolean 

scala> val f1 = typedFunction[String] 
f1: String => Boolean = <function1> 

scala> val f2 = typedFunction[Int] 
f2: Int => Boolean = <function1> 

scala> f1 eq f2 
res0: Boolean = true 

To działa, ponieważ trait Function1[-T1, +R] jest kontrawariantny typu T1.

+0

Ah prawda. To jest faktycznie po prostu rzucanie do bardziej ograniczonego typu. W rzeczywistości możemy całkowicie zrezygnować z tej metody i po prostu przypisać funkcję, np. 'val f1: String => Boolean = funObj' – erich2k8

7

Tak jak mówisz, w twoim przykładzie wszystko, czego potrzebujesz, to metoda toString, a więc standardowe rozwiązanie. Istnieje jednak potrzeba korzystania z typów wyższego rzędu w sytuacjach takich, jak zastosowanie konstruktora typu, takiego jak List, do każdego elementu krotki.

jak inne odpowiedzi wspomniałem, nie ma bezpośredniego wsparcia dla tego, ale jest stosunkowo dobry sposób, aby go zakodować:

trait ~>[A[_],B[_]] { 
    def apply[X](a : A[X]) : B[X] 
} 

type Id[A] = A //necessary hack 

object newList extends (Id ~> List) { 
    def apply[X](a : Id[X]) = List(a) 
} 

def tupleize[A,B, F[_]](f : Id ~> F, a : A, b : B) = (f(a), f(b)) 

tupleize(newList, 1, "Hello") // (List(1), List(Hello)) 
1

w Scala, wartości funkcji są parametrycznie jednokształtny (gdy metody są polimorficzne)

Biblioteka bezkształtna przedstawia wartości funkcji polimorficznych, które mogą być mapowane na HList i wiele innych funkcji.

Proszę wziąć pod uwagę następujące pozycje literaturowe: http://www.chuusai.com/2012/04/27/shapeless-polymorphic-function-values-1/ http://www.chuusai.com/2012/05/10/shapeless-polymorphic-function-values-2/

+0

Podczas gdy ten link może odpowiedzieć na pytanie, lepiej umieścić tutaj istotne części odpowiedzi i podać odnośnik. Odpowiedzi dotyczące linków mogą stać się nieprawidłowe, jeśli strona z linkami się zmieni. – Sasa

+0

@Sasam, że odpowiedź zawiera zasadniczą część odpowiedzi! –

Powiązane problemy