1

I know I can define a function def foo(): Int => String that returns a function that accepts an integer and returns a string. However, I want to return a slightly more complicated function with both generics and implicits. In other words, I want to be able to say something like def foo(): [T](T)(implicit T) => T. Ideally for the generics I would prefer not to have to define foo with the type parameter def foo[T] - I want T to be determined only when the function returned from foo is invoked.

dertkw
  • 7,798
  • 5
  • 37
  • 45
Kvass
  • 8,294
  • 12
  • 65
  • 108
  • 1
    a *value* can't be generic – Display Name Jun 13 '14 at 16:49
  • 1
    `foo` is a *method*, *not* a *function*. See http://stackoverflow.com/questions/2529184/difference-between-method-and-function-in-scala. I point this out not to be pedantic, but because it's of critical importance to your question. – Aaron Novstrup Jun 13 '14 at 17:24
  • 1
    This may also be of interest: http://www.chuusai.com/2012/05/10/shapeless-polymorphic-function-values-2/ – Aaron Novstrup Jun 13 '14 at 17:38

2 Answers2

1

As Miles Sabin explains in far more detail (and far more eloquently) in his blog post on first-class polymorphic function values, your goal can be achieved with some effort. "A value can't be generic" is correct insofar as Scala's built-in function values are concerned, but function-like objects can define a generic apply method (and therefore act as a generic function at the callsite):

class Foo {
  def apply[T, E, R](x: T)(implicit e: E): R = ???
}

def foo = new Foo

val fn = foo // fn is effectively a generic function value!
Aaron Novstrup
  • 20,967
  • 7
  • 70
  • 108
1

Another link to help you on your way http://existentialtype.net/2008/05/26/revisiting-higher-rank-impredicative-polymorphism-in-scala/

trait forall[P[_]] {
  def apply[A]: P[A]
}

trait Nat[F[_], G[_]] {
  def apply[A](x: F[A]): G[A]
}

def foo: forall[({ type λ[τ] = τ => String })#λ] = ???

Above are some types that might help you write at the level of generality (generic-ness?) you're seeking. As commented above "a value can't be generic ..." and as mentioned above by Mr Norvstrup, in scala functions aren't always functions. Sometimes they're methods and somewhere in the scala language spec, it's detailed the relationship between method values and function values, methods aren't value types but that's a little beside the point for what you're trying to do above. What's especially key in what you're trying to do is name binding. The link I posted along with the links in Mr. Novstrup's answer explain it way better than I could, but the gist AFAIU is when a particular type is chosen. In the ordinary function type in the scala std lib, which is a little like

trait function[T, R] {
  def apply(x: T): R
}

the domain and codomain types of the function are chosen at the definition of the function where as in types like forall or Nat (which is a way of encoding natural transformations, but that's for another time) the type A is chosen later at the call site, which is more what you want. Hopefully my answer provides a little more detail.

Mzk Levi
  • 814
  • 7
  • 14