将具有 N 个参数的 def 实现为 FunctionN 类型的 val

发布于 2024-08-19 15:49:07 字数 611 浏览 12 评论 0原文

我可以使用 val 实现 def,其中 def 不带任何参数:

trait T { def foo: Int }
class C(val foo: Int) extends T

为什么不能将其扩展为实现 def< /code> 将 N 个参数传入一个 FunctionN 的 val?我希望能够实现类似的东西:

def expensiveOperation(p: Int => Boolean) : List[Int]

使用惰性函数val。比如:

val expensiveOperation = {
    val l = //get expensive list
    l.filter _ //partially applied function
}

我知道这个语法似乎不适用于 2.8。我是否遗漏了什么,为什么我不能实现将参数作为函数valdef

I can implement a def with a val where the def takes no arguments:

trait T { def foo: Int }
class C(val foo: Int) extends T

Why can this not be extended to implementing a def taking N args to a val which is a FunctionN? I want it possible to implement something like:

def expensiveOperation(p: Int => Boolean) : List[Int]

With a lazy function val. Something like:

val expensiveOperation = {
    val l = //get expensive list
    l.filter _ //partially applied function
}

I know that this syntax does not seem to work on 2.8. Is there something I'm missing, why can I not implement a def taking parameters as a functional val?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

明媚如初 2024-08-26 15:49:07

现在,后期编辑,我想我明白你在追求什么。但你不能做你想做的事,因为类型签名不匹配。

def x: Int = 5
val x: Int = 5

在这两种情况下,您什么都不提供并返回一个 Int(在本例中为 5)。伟大的!

def expensive(p: Int => Boolean): List[Int]

现在你提供一些东西。但 val 只是某个地方存储的对象。您可以向标签引用的对象提供一些内容,但这与向标签“x”提供一些内容不同。

如果您希望 val 覆盖它,则需要使用以下 def:

def expensive: (Int=>Boolean)=>List[Int]

现在,您可以不带参数调用某些内容,并且它返回可以采用 Int=>Boolean 函数并返回 List[Int] 的内容。这正是您通过 val 得到的结果——在这两种情况下,您都拥有返回具有您想要的功能的对象的名称。

(在 Scala 中,val 实际上是作为带有 getter 方法的隐藏字段实现的,这些方法不带参数并返回隐藏字段中的任何内容。所以它确实是一个与 def 一样的方法。)

Now, post-edits, I think I understand what you're after. But you can't do what you want because the type signatures don't match.

def x: Int = 5
val x: Int = 5

In both cases you supply nothing and get back an Int (in this case 5). Great!

def expensive(p: Int => Boolean): List[Int]

Now you supply something. But a val is just a stored object somewhere. You can supply something to the object that the label refers to, but that's not the same as supplying something to the label 'x'.

Here's the def you need to use if you want a val to override it:

def expensive: (Int=>Boolean)=>List[Int]

Now you have something that you call with no parameters and it returns something that can take a Int=>Boolean function and give you a List[Int] in return. That's exactly what you get with the val--in both cases, you have the name of something that returns an object that has the functionality you want.

(In Scala, vals are actually implemented as hidden fields with getter methods that take no parameters and return whatever's in the hidden field. So it really is a method just like the def is.)

只是一片海 2024-08-26 15:49:07

val 不接受参数,因为它是计算并存储在字段中的。但我可能只是建议您参考我过去两天在邮件列表上发表的大量帖子。

或者更确切地说,让我们从 Java 的角度来考虑,因为 Scala 在 jvm 层面与 Java 兼容,并且它肯定必须遵守 jvm 规则。让我们从第一个类开始:

abstract class X {
  def expensiveOperation(p: Int => Boolean) : List[Int] 
}

现在,让我们扩展它:

abstract class Y extends X {
  override val expensiveOperation: ((Int) => Boolean) => List[Int]
}

因此,从 Java 中,我们知道类 X 具有方法 expenseOperation,该方法接收 Function1[Int , Boolean] 并返回 List[Int]

现在我们进入Y类。当然,它必须定义相同的方法,但它还必须定义 getter exppressiveOperation,它不接收参数并返回 Function1[Function1[Int, Boolean],List[Int]]

只要 X 中不存在此附加方法,它就可能是可行的。那么让我们来定义它:

class Z extends Y {
  override val extensiveOperation = new Function1[Function1[Int, Boolean], List[Int]] {
    def apply(p: Int => Boolean) = List range (1, 10) filter p
  }
}

如何定义它? Scala 是否将 apply 的主体复制为 exppressiveOperation 的主体(接收参数的主体,而不是 getter 的主体)?它可能仍然可行。不过,让我们尝试其他方法:

class W(f: ((Int) => Boolean) => List[Int]) extends Y {
  override val extensiveOperation = f
}

现在,我们如何重写参数接收 extenseOperation?我想我们可以这样写:

override def extensiveOperation(p: Int => Boolean) = extensiveOperation.apply(p)

这是可行的。但我个人认为这有点复杂。我的建议:写一个简短的 SID,并在 Scala 邮件列表上达成一些协议。不过,如果没有代码来实现它,我认为它被采用的机会不大——Scala 必须跟踪每个函数类型的 val 来确定它是否覆盖了 def< /code> 或不。

A val doesn't take arguments, because it is computed and stored in a field. But I might just refer you to the extensive posts I did the last two days on the mailing lists.

Or, rather, let's consider it from a Java point of view, since Scala is compatible with Java at the jvm level, and it surely must obey jvm rules. Let's start with the first class:

abstract class X {
  def expensiveOperation(p: Int => Boolean) : List[Int] 
}

Now, let's extend it:

abstract class Y extends X {
  override val expensiveOperation: ((Int) => Boolean) => List[Int]
}

So, from Java, we know that class X has the method expensiveOperation, which receives Function1[Int, Boolean] and returns List[Int].

Now we go to class Y. Naturally, it has to define the same method, but it also has to define the getter expensiveOperation, which receives no arguments and returns Function1[Function1[Int, Boolean],List[Int]].

It might be workable, as long as this additional method didn't exist in X too. So let's define it:

class Z extends Y {
  override val extensiveOperation = new Function1[Function1[Int, Boolean], List[Int]] {
    def apply(p: Int => Boolean) = List range (1, 10) filter p
  }
}

How does that get defined? Does Scala copy apply's body as a body for expensiveOperation (the one receiving a parameter, not the getter one)? It might still be workable. Let's try something else, though:

class W(f: ((Int) => Boolean) => List[Int]) extends Y {
  override val extensiveOperation = f
}

Now, how do we override the parameter-receiving extensiveOperation? I suppose we could write it like this:

override def extensiveOperation(p: Int => Boolean) = extensiveOperation.apply(p)

That's workable. But I, personally, think it is a bit convoluted. My suggestion: write up a short SID, and get some agreement on a Scala mailing list. Without code to implement it, though, I don't think it has much chance of being adopted -- Scala has to track every function-typed val to figure if it is overriding a def or not.

网名女生简单气质 2024-08-26 15:49:07

您始终可以将其转发给您的 val:

trait T {
  def expensiveOperation(p: Int => Boolean) : List[Int]
}

class C extends T {
  def expensiveOperation(p: Int => Boolean): List[Int] = {
      expensiveOperationVal(p) 
  }
  val expensiveOperationVal = { p: (Int=>Boolean) =>
    // ... lazy stuff
    List(1,2,3)
  }
}

并且,尽管这不能回答您的问题,但看起来除非您的 // ... get昂贵列表 代码取决于谓词 p,那么你可以做类似的事情:

class C extends T {
  def expensiveOperation(p: Int => Boolean): List[Int] = {
      myExpensiveList filter p 
  }
  lazy val myExpensiveList = {
    val l = // ... expensive stuff
    l
  }
}

You could always just forward it to your val:

trait T {
  def expensiveOperation(p: Int => Boolean) : List[Int]
}

class C extends T {
  def expensiveOperation(p: Int => Boolean): List[Int] = {
      expensiveOperationVal(p) 
  }
  val expensiveOperationVal = { p: (Int=>Boolean) =>
    // ... lazy stuff
    List(1,2,3)
  }
}

And, although this doesn't answer your question, It looks like unless your // ... get expensive list code depends on the predicate p, then you could just do something similar to:

class C extends T {
  def expensiveOperation(p: Int => Boolean): List[Int] = {
      myExpensiveList filter p 
  }
  lazy val myExpensiveList = {
    val l = // ... expensive stuff
    l
  }
}
不语却知心 2024-08-26 15:49:07

编辑:好吧,我没明白你的意思。但是,如果您的意思是我的想法...

您可以使用缩写语法创建一个应用操作的 val:

val expensive = (p: (Int) => Boolean) => {
  val l = List(1,2,3,4)
  l filter p
}
scala> expensive(_<3)
res1: List[Int] = List(1,2)

但这实际上并没有缓存列表,这正是我认为您想要的。原因是这种简写语法将所有内容放在=>之后。进入Function1的apply方法。您可能希望像这样存储列表:

val expensive = new Function1[Int=>Boolean,List[Int]] {
  lazy val l = List(1,2,3,4)
  def apply(p: (Int) => Boolean) = { l filter p }
}

据我所知,对此没有很好的速记。

编辑:如果您很乐意在该块之外创建列表,那么有一个简写(另请参阅评论):

val expensive = List(1,2,3,4).filter _

scala> expensive(_ < 3)
res6: List[Int] = List(1, 2)

Edit: okay, I didn't figure out what you actually meant. But if you had meant what I thought...

You can, using abbreviated syntax, create a val that applies an operation:

val expensive = (p: (Int) => Boolean) => {
  val l = List(1,2,3,4)
  l filter p
}
scala> expensive(_<3)
res1: List[Int] = List(1,2)

But this doesn't actually cache the list, which is what I think you want. The reason is that this short-hand syntax puts everything after => into the apply method of Function1. You probably want the list to be stored like so:

val expensive = new Function1[Int=>Boolean,List[Int]] {
  lazy val l = List(1,2,3,4)
  def apply(p: (Int) => Boolean) = { l filter p }
}

and for that there isn't a great shorthand that I know of.

Edit: If you're happy to create the list outside of that block, then there is a shorthand (see comment also):

val expensive = List(1,2,3,4).filter _

scala> expensive(_ < 3)
res6: List[Int] = List(1, 2)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文