Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Scala, is it possible to "curry" type parameters of a def?

Let's suppose I have a def that takes multiple type parameters:

def foo[A, B, C](b: B, c: C)(implicit ev: Writer[A])

However, the intended usage is that type parameters B and C should be inferred (based on the passed-in arguments). And the caller should only need to really specify A explicitly (e.g. to have an appropriate implicit chosen by the compiler). Unfortunately, Scala only allows all or none of the type parameters to be specified by the caller. In a sense, I want the type parameters to be curried:

def foo[A][B, C]...

Is there some trick to accomplish this in Scala?

(If my specific example doesn't make complete sense I'm happy to improve it with suggestions.)

like image 340
tksfz Avatar asked Aug 17 '16 04:08

tksfz


People also ask

What is curried function in Scala?

Currying is the process of converting a function with multiple arguments into a sequence of functions that take one argument. Each function returns another function that consumes the following argument.

What is a type parameter Scala?

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


1 Answers

The best way I've been able to pull this off is by defining a class which holds the curried type information then uses the apply method to simulate the function call.

I've written about this here - http://caryrobbins.com/dev/scala-type-curry/

For your specific example, you'd need to put the implicit ev: Writes[A] in the signature for the apply and not in the signature for foo. This is because it causes ambiguity between explicitly passing the implicit argument or implicitly calling the apply method.

Here's an example implementation for your example -

object Example {
  def foo[A]: _Foo[A] = _foo.asInstanceOf[_Foo[A]]

  final class _Foo[A] private[Example] {
    def apply[B, C](b: B, c: C)(implicit ev: Writes[A]): Unit = ???
  }

  private lazy val _foo = new _Foo[Nothing]
}

You can then supply your type parameter you wish to curry and the following arguments passed to the apply method will be inferred.

Example.foo[Int]("bar", new Object)

If you do end up needing to specify the other type parameters, you can do so by explicitly calling apply; although, I've never seen a need to do this yet.

Example.foo[Int].apply[String, Object]("bar", new Object)

If you don't wish to use the intermediate type you can also use a structural type, which I discuss in the aforementioned post; however, this requires reflectiveCalls and an inferred type signature, both of which I like to avoid.

like image 129
pyrospade Avatar answered Sep 17 '22 13:09

pyrospade