Scala:如何编写一个通用检查函数来计算任何返回布尔值的函数?

时间:2013-06-06 02:51:05

标签: function scala generics

我正在努力解决这个问题:我需要一个能够执行任何功能的函数 fun类型(Any *):Boolean作为参数,计算函数并返回true或 是的,取决于功能评估的成功。

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

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

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)返回类型布尔的另一个函数:“(func:=&gt; Boolean)” 2)返回类型Boolean“:Boolean” 3)返回传递的函数参数的值:“= func”

这个功能总是:

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

令我惊讶的是,Scala中的简单事物是多么简单。

正如评论所指出的,这是一个相当不寻常的功能,没有明显的 感。只是关于潜在原因的一句话。

动机:

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

基本上,有两个原因。

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

其次,关键是“可插拔故障处理”。这意味着,仅限eval函数 告知是否发生了故障。如果发生故障,则通过接口调用处理程序。可以根据需要使用配置文件交换处理程序的实现。

为什么呢?

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

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


解决

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

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

2 个答案:

答案 0 :(得分:2)

我不能说我真的理解你想要做你想做的事情的动机,但我想这不是重点。也许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-name函数,然后利用闭包在by-name函数中,将任何参数传递给你想要调用的任何实际函数。证明这一点的更好方法如下:

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的参数来调用函数。

这只是解决问题的一种方法,根据您的需要,它甚至可能不合适,但我只是想把它扔出去。

答案 1 :(得分:1)

如果你的输入函数只有2个参数,就像你的两个例子一样,你可以编写一个半泛型函数take take all with two arguments of any type:

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函数。

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