Can you curry a function with varargs in scala?

ε祈祈猫儿з 提交于 2019-12-10 15:08:08

问题


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.


回答1:


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


来源:https://stackoverflow.com/questions/13778545/can-you-curry-a-function-with-varargs-in-scala

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!