I was thinking about how to go about currying a method with varargs, and I realized that I don't even have an intuition for how one would go about doing it. Ideally, it would be something that would let you start using it whenever you liked, and then end it with an iterable.
def concat(strs: String*) = strs.mkString
val curriedConcat = concat.curry
curriedConcat("OK")("hello", "world")("welcome")(Seq(): _*)
Is there support for this in scala? I couldn't figure out how to do anything more than bind it to a function of length N and then curry that.
Using Scala 2.10 and shapeless:
import shapeless.Nat._
import shapeless.{Nat, Succ}
trait Curry[T, Res, N <: Nat] {
type Out
def apply(as: Seq[T], f : Seq[T] => Res) : Out
}
object Curry {
implicit def curry[Out0, T, Res, N <: Nat](implicit curry : CurryAux[Out0, T, Res, N]) = new Curry[T, Res, N] {
type Out = Out0
def apply(as: Seq[T], f : Seq[T] => Res) = curry(as, f)
}
}
trait CurryAux[Out, T, Res, N <: Nat] {
def apply(as: Seq[T], f : Seq[T] => Res) : Out
}
object CurryAux {
implicit def curry0[Res, T] = new CurryAux[Res, T, Res, _0] {
def apply(as: Seq[T], f : Seq[T] => Res) : Res = f(as)
}
implicit def curryN[Out, T, Res, N <: Nat](implicit c : CurryAux[Out, T, Res, N]) =
new CurryAux[T => Out, T, Res, Succ[N]] {
def apply(as: Seq[T], f : Seq[T] => Res) : (T => Out) = (a: T) => c(as :+ a, f)
}
}
implicit class CurryHelper[T, Res](f : Seq[T] => Res) {
def curry[N <: Nat](implicit c : Curry[T, Res, N]): c.Out = c(IndexedSeq[T](), f)
}
Usage:
scala> def concat(strs: String*) = strs.mkString
concat: (strs: String*)String
scala> val test = ( concat _ ).curry[_3]
test: String => (String => (String => String)) = <function1>
scala> test("1")("2")("3")
res0: String = 123
Without shapeless:
class CurryHelper[T, Res](f: Seq[T] => Res, as: Seq[T]) {
def myCurry() = this
def apply(ts: T*) = new CurryHelper(f, as ++ ts)
def apply(ts: Seq[T]) = f(as ++ ts)
}
implicit def toCurryHelper[T, Res](f: Seq[T] => Res) = new CurryHelper(f, IndexedSeq[T]())
scala> def concat(strs: String*) = strs.mkString
concat: (strs: String*)String
scala> val test = ( concat _ ).myCurry
test: CurryHelper[String,String] = CurryHelper@4f48ed35
scala> test("1")("2")("3", "4")(Nil)
res0: String = 1234
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With