【问题标题】:Scala: How to write a generic check function that evaluates any function that returns boolean?Scala:如何编写一个通用的检查函数来评估任何返回布尔值的函数?
【发布时间】:2013-06-06 02:51:04
【问题描述】:

我有点挣扎:我需要一个可以接受任何函数的函数 fun(Any*) 类型:布尔值作为参数,计算函数并返回 true 或 false,取决于函数评估的成功。

本质上,我需要的是一个函数类型,它允许任何数量和任何类型的参数,但该函数必须返回布尔值。

这将允许我编写如下函数:

def checkLenght(str : String, length : Int) : Boolean ={
if (str.lenght == length)}

def ceckAB(a : Int, b : Int) : Boolean = {
if(a < b && a >= 23 && b < 42) }

这样,例如

eval(checkLenght(abc, 3)) //returns true

eval(ceckAB(4,1)) // returns false 

我想,一个函数类型:

  type CheckFunction = (Any*) => Boolean

可能会成功,但我在编写通用 eval 函数时遇到了困难。

有什么建议吗?

谢谢

解决办法:

该功能需要 1) 另一个返回类型为 Boolean 的函数:“(func : => Boolean)” 2)返回类型布尔“:布尔” 3) 返回传递的函数参数的值:“= func”

总的功能是:

   def eval(func : => Boolean) : Boolean = func

让我再次惊讶于 Scala 中的简单事物是多么简单。

正如 cmets 所指出的,这是一个相当不寻常的功能,没有明显的 感觉。简单说一下根本原因。

动机:

有很多关于潜在动机的问题,所以这里简短 总结为什么需要这样的功能。

基本上有两个原因。

第一个是关于将故障处理从函数本身移开 进入处理函数。这保留了检查功能的纯度,甚至允许 重用通用检查。

其次,这一切都与“可插拔故障处理”有关。这意味着,只有 eval 函数 告诉是否发生了故障(或没有发生)。如果发生故障,则通过接口调用处理程序。可以根据需要使用配置文件交换处理程序的实现。

为什么?

交换配置文件意味着,我像往常一样编写我的检查和功能,但通过切换 配置文件,我切换处理程序,这意味着我可以在句号、控制台打印输出、电子邮件警报、SNMP 通知、推送消息之间进行选择......你可以命名它。为此,我需要将检查函数与其评估和处理分离。这就是这种看起来相当奇怪的 eval 函数的动机。

为了完整起见,我已经实现了所有这些东西,但我是否面临只处理琐碎检查的限制,即 check(Boolean*) 这很简洁,但我通常更愿意编写一个函数来做更多事情复杂的检查。


已解决

通过返回传递函数的值来定义函数:

def eval(func : => Boolean) : Boolean = {func}

【问题讨论】:

  • 在您的示例中,eval 函数不会做任何事情:您将布尔值(函数调用)作为参数传递给它,它返回相同的布尔值...
  • 问题不清楚。您的问题的性质如何使您无法简单地应用您定义的布尔值函数?如果你想提供参数但延迟实际评估,你可以让你的函数有一个额外的单位类型的咖喱参数;那么eval 将是(Unit =&gt; boolean) =&gt; boolean 定义为f =&gt; f()。不是很有趣。
  • 我同意之前所说的;如果您想要做的只是返回您传入的函数调用返回的值,那么eval 只是作用域为Boolean 类型值的identity 函数,所以这很好:val eval = identity[Boolean] _跨度>
  • Wilfried,我觉得你的解决方案很有趣。身份[T] 是否在 predef 中定义?这是我第一次看到。

标签: function scala generics


【解决方案1】:

我不能说我真的理解你想做自己想做的事的动机,但我想这不是重点。也许eval 函数会在调用提供的函数之前检查某些内容,而不是在某些特定条件下调用其他函数(如快速失败)。也许您在调用该函数后进行了一些后期检查,并根据其他内容更改结果。无论哪种方式,我想您都可以使用如下代码完成与您想要的类似的事情:

def main(args: Array[String]) {
  val str = "hello world"
  println(eval(checkLength(str, 3)))
  println(eval(intsEqual(1,1)))
}

def eval(func: => Boolean):Boolean = {
  //Do whetever you want before invoking func, maybe
  //not even invoke it if some other condition is present
  val fres = func

  //Maybe change something here before returning based on post conditions
  fres
}

def checkLength(s:String, len:Int) = s.length() == len
def intsEqual(a:Int, b:Int) = a == b

如果您真的希望 eval 函数能够支持任何接受任何类型的 args 并返回 Boolean 的函数,那么使用像这样的别名函数,然后在 by- 中利用闭包命名函数以将任何参数传递给您要调用的任何实际函数。证明这一点的更好方法如下:

def checkMyString(str:String, len:Int) = {
  eval(str.length == len)
}

可能很难看出检查 str.length == len 不会被调用,除非 eval 决定调用它,直到你将它扩展为它的真实形式:

def checkMyString(str:String, len:Int) = {
  def check = {
   str.length == len 
  }
  eval(check)
}

在这里,嵌套函数 check 可以访问 strlen 由于关闭,这将允许您绕过 eval 必须能够调用具有任何参数的函数的要求返回一个Boolean

这只是解决您的问题的一种方法,它甚至可能不适合您的需求,但我只是想把它扔在那里。

【讨论】:

  • 谢谢,我已将您的解决方案标记为答案,并更新了问题的一些详细信息,以了解潜在动机。
  • 很好的解决方案。最后一个例子的另一种写法是def checkMyString(str:String, len:Int) = eval { str.length == len }
【解决方案2】:

如果您的输入函数只有 2 个参数,就像您的两个示例一样,您可以编写一个半通用函数 take 接受所有具有两个任意类型参数的函数:

def eval[A,B](func: (A,B) => Boolean, arg1: A, arg2: B) = {
    func(arg1, arg2)
}

def checkLength(str: String, length: Int) : Boolean = {
    str.length == length
}

eval(checkLength, "ham", 4)
res0: Boolean = false

但是如果你想支持更多参数的函数,你就必须为三个参数、四个参数等编写一个eval函数

也许有更好的方法可以处理所有情况?

【讨论】:

  • 你可以用一个 scala 宏完全通用地完成它,但它可能需要更多的工作而不是它的价值。
  • 是的,有一个更好的方法,没有宏: def eval(func : => Boolean) : Boolean = func
猜你喜欢
  • 2020-03-04
  • 1970-01-01
  • 2011-06-12
  • 2014-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-05
  • 2012-12-25
相关资源
最近更新 更多