Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Scala, can generic type parameters be used with *function* definitions?

Tags:

generics

scala

Is there a syntax to allow generic type parameters on function literals? I know I could wrap it in a method such as:

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

but then I end up needing to invoke the method for every type T and getting a new function. I looked through the language reference, and while I see that the function literal syntax is translated by the compiler to an instance of a Functionn object that itself has generic input types, it looks like the compiler magic realizes those parameters at the time of creation. I haven't found any syntax that allows me to, in effect, "leave one or more of the type parameters of Functionn unbound". What I would prefer is something along the lines of:

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

Does any such thing exist? Or for that matter, what is the explicit type of an eta-expansion function when the method being expanded has generic parameters?

This is a purely contrived and useless example. Of course I could just make the function use Any here.

like image 533
Eric Haynes Avatar asked Mar 07 '13 06:03

Eric Haynes


People also ask

What is generic function in Scala?

One of the best ways to understand use cases for generic classes is to look at examples in the Scala standard library. Most Scala generic classes are collections, such as the immutable List, Queue, Set, Map, or their mutable equivalents, and Stack. Collections are containers of zero or more objects.

How do I use generic in Scala?

To use a generic class, put the type in the square brackets in place of A . Class Apple and Banana both extend Fruit so we can push instances apple and banana onto the stack of Fruit . Note: subtyping of generic types is *invariant*.

What is a type parameter Scala?

Language. Methods in Scala can be parameterized by type as well as value. The syntax is similar to that of generic classes. Type parameters are enclosed in square brackets, while value parameters are enclosed in parentheses.

What is a generic type parameter?

Generic Methods A type parameter, also known as a type variable, is an identifier that specifies a generic type name. The type parameters can be used to declare the return type and act as placeholders for the types of the arguments passed to the generic method, which are known as actual type arguments.


2 Answers

No, type parameters only apply to methods and not function objects. For example,

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

The method f cannot be converted to a polymorphic function object g. As you can see, the inferred type of g is actually Function1[Nothing, Nothing], which is useless. However, with a type hint we can construct h: Function1[Int,Int] that works as expected for Int argument.

like image 135
Kipton Barros Avatar answered Sep 21 '22 21:09

Kipton Barros


As you say, in your example all you're requiring is the toString method and so Any would be the usual solution. However, there is call for being able to use higher-rank types in situations such as applying a type constructor such as List to every element in a tuple.

As the other answers have mentioned, there's no direct support for this, but there's a relatively nice way to encode it:

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))
like image 33
Impredicative Avatar answered Sep 23 '22 21:09

Impredicative