3

我希望能够将一个函数传递给一个类,以便该函数始终返回一个布尔值,但参数的数量可以是可变的。

这实际上是我现在正在使用的:

/**
  * Template class for any SecureSocial SecuredAction.
  */
class SomeAction[T](
    isSuccessful: (SecuredRequest[AnyContent], T) => Boolean, 
    success: Result, 
    failure: Result) extends SecureSocial {

      def toReturn = SecuredAction(WithProvider("google")) {
        implicit request => if (isSuccessful(request)) success else failure
      }

}

我希望isSuccessful参数是一个函数,它至少接受一个类型的参数SecuredRequest[AnyContent]和一个零个或多个参数。有时我会传入一个只需要request对象的函数,有时我会传入一个需要request对象和一些其他参数的函数。

看到这个答案后,我查看了 currying,这是将多参数函数转换为单参数函数的做法,如果需要更多参数,它将返回一个函数。这听起来可以解决我的问题,但是在阅读了部分应用函数和 currying 之间的区别之后,我开始认为不是?看起来仍然有一定数量的最终论点......

我想成功的咖喱会是这样的:

class SomeAction[T](
    isSuccessful : ((SecuredRequest[AnyContent])(T) => Boolean) ,  // ERROR
    ... ) ... { ... }

这绝对不是正确的语法。

或者

class SomeAction[T](
    isSuccessful : (SecuredRequest[AnyContent] => Boolean) , 
    ... ) ... { ... }

做一些事情isSuccessfultoReturn取消传递的函数。

可能导致我回答的多个问题:

  • 是否有一些特殊的语法来描述我不知道的柯里化函数?
  • 或者我有一个类型(SecuredRequest[AnyContent] => Boolean)函数,但是在调用时做一些 uncurrying isSuccessful(request)

谢谢阅读; 我想我只是在寻找简单的例子。

4

3 回答 3

1

如果你有ftype的方法(A*)B,那么 eta-expandedf _就是Seq[A] => B

在 内部f,重复的参数Seq[A]无论如何都有类型,所以它是有道理的。

有一张著名的车票:

https://issues.scala-lang.org/browse/SI-4176

它以立即弃用的选项-Yeta-expand-keeps-star 而闻名。

这是一个方法示例,该方法采用箭头左侧带有星号的函数并调用它。

因此,如果“任意数量”是指“任意数量的Ts”,例如 type T = (String, String),那么 varargs 就足够了。

object Test extends App {

  def f(g: (Int*) => Int) = g(1,2,3)

  def sum(is: Int*) = is.sum

  Console println f(sum _)

  def f2(g: (Int*) => Int, h: =>Seq[Int]): Int = g(h: _*)

  Console println f2(sum _, List(1,2,3))

  def f3(g: (Int*) => Int, is: Int*): Int = g(is: _*)

  Console println f3(sum _, 1,2,3)
}
于 2013-07-26T23:59:50.680 回答
1

如果您的函数采用可变数量的参数,则可以这样做。这是必需的,因为他们事先不知道该操作将提供多少参数。正如其他人提到的,可变参数函数被翻译为最后一个参数是序列的函数。所以你可以做这样的事情:

case class Action[T](f: (String, Seq[T]) => Boolean);

def testfn(s: String, args: Int*): Boolean = true;

new Action[Int](testfn _);

如果你需要你的函数来表示它们有错误数量的参数,你可以让它们返回Option,也许为各种 arities 添加一些辅助函数,比如

case class Action[T](f: (String, Seq[T]) => Option[Boolean]);

然后,如果给定的参数数量错误,您可以为不同的参数提供帮助,将“正常”函数转换为可变None参数:

// for 1 argument functions:
def toVar[T](f: (String, T) => Boolean)(s: String, xs: Seq[T]): Option[Boolean] =
  Some(xs).collect({ case Seq(x1) => f(s, x1) });
// for 2 argument functions:
def toVar[T](f: (String, T, T) => Boolean)(s: String, xs: Seq[T]): Option[Boolean] =
  Some(xs).collect({ case Seq(x1, x2) => f(s, x1, x2) });

def testfn(s: String, x1: Int, x2: Int): Boolean =
  (x1 == x2);

new Action[Int](toVar(testfn _));

如果您为刚刚调用的不同参数和主构造函数toVar创建专门的构造函数,您甚至可以避免。ActiontoVar

于 2013-07-27T12:01:22.383 回答
0

知道了。

/**
  * Template class for any SecureSocial SecuredAction that involves using user information.
  * @param isSuccessful: SecuredRequest[AnyContent] => Boolean
  */
class UserReqAction(
  isSuccessful: (SecuredRequest[AnyContent] => Boolean),
  success: Result, failure: Result) extends SecureSocial {
  def toReturn = SecuredAction(WithProvider("google")) {
    implicit request => if (isSuccessful(request)) success else failure
  }
}

/**
  * Template class for any SecureSocial SecuredAction that does not use user information.
  * @param isSuccessful: SecuredRequest[AnyContent] => Boolean
  */
class UserNotReqAction(isSuccessful: () => Boolean,
                       success: Result, failure: Result) extends SecureSocial {
  def toReturn = SecuredAction(WithProvider("google")) {
    implicit request => if (isSuccessful()) success else failure
  }
}

// not curried example
def makeNewThing = new UserReqAction(
  userOp.createThing,
  Ok(Json.toJson(Json.obj("success" -> true, "msg" -> "Thing successfully created"))),
  BadRequest("failed to create Thing")).toReturn

// curried example
def editThing(param1: _, param2: _, etc) = new UserReqAction(
  userOp.updateThing(param1, param2, etc), // this is the currying
  Ok(Json.toJson(Json.obj("success" -> true, "msg" -> "Thing successfully edited"))),
  BadRequest("failed to edit Thing")).toReturn

def updateThing(param1: _, param2: _, etc)(request: SecuredRequest[AnyContent] ) {...}
于 2013-07-26T22:01:53.970 回答