【问题标题】:Can you curry a function with varargs in scala?你可以在 Scala 中使用可变参数来咖喱一个函数吗?
【发布时间】:2012-11-26 13:03:07
【问题描述】:

我在考虑如何使用可变参数来柯里化一个方法,但我意识到我什至没有直觉知道如何去做。理想情况下,它可以让您随时开始使用它,然后以可迭代的方式结束它。

def concat(strs: String*) = strs.mkString

val curriedConcat = concat.curry

curriedConcat("OK")("hello", "world")("welcome")(Seq(): _*)

scala 对此有支持吗?除了将它绑定到长度为 N 的函数然后 curry 之外,我不知道如何做任何事情。

【问题讨论】:

  • scala 中没有“带可变参数的函数”之类的东西。只有methods这样的。
  • 我不认为这是正确的。我在我的示例中使用了一个方法,但我可以使用一个函数。这是一个简单的构造方法: scala> def concat(first: String)(strs: String*) = first + strs.mkString concat: (first: String)(strs: String*)java.lang.String scala> val func = concat("NOK")_ func: String* => java.lang.String =
  • 是的,它在 2.9 中工作,但在 Scala 2.10 中,对带有可变参数的函数对象的支持已被删除。
  • 好的,很高兴知道。我使用的是 scala 2.9.2,但我会更改问题,以便准确反映 scala 2.10 的美好新世界。
  • String* => String 是非常奇怪的类型。不能作为参数传递,所以没用。

标签: scala functional-programming currying


【解决方案1】:

使用 Scala 2.10 和无形:

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)
}

用法:

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

无形:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-02
    • 2016-10-20
    • 1970-01-01
    • 2013-08-26
    • 1970-01-01
    • 2011-04-21
    相关资源
    最近更新 更多