Scala - 柯里化和默认参数

发布于 2024-11-01 04:31:00 字数 1038 浏览 1 评论 0原文

我有一个带有两个参数列表的函数,我试图部分应用并与柯里化一起使用。第二个参数列表包含所有具有默认值(但不是隐式的)的参数。像这样的事情:

 def test(a: Int)(b: Int = 2, c: Int = 3) { println(a + ", " + b + ", " + c); }

现在,以下都很好:

 test(1)(2, 3);
 test(1)(2);
 test(1)(c=3);
 test(1)();

现在如果我定义:

 def partial = test(1) _;

那么可以完成以下操作:

 partial(2, 3);

有人可以解释为什么我不能省略“部分”中的某些/所有参数,如下所示:

 partial(2);
 partial(c=3);
 partial();

不应该写“部分” ” 的行为本质上与“test(1)”相同?有人可以帮我想出一种方法来实现这一目标吗?

请帮忙,我很绝望!

编辑 - 由于我无法在 24 小时内回答我自己的问题,我将在这里发布我自己的答案:

这是迄今为止我自己能做的最好的事情:

class Test2(val a: Int) {
   def apply(b: Int = 2, c: Int = 3) { println(a + ", " + b + ", " + c); }
}

def test2(a: Int) = new Test2(a);
def partial2 = test2(1); // Note no underscore

test2(1)(2, 3);
test2(1)(2);
test2(1)(c=3);
test2(1)();

partial2(2, 3)
partial2(2);
partial2(c=3);
partial2();

这样就可以了......

I have a function with two parameter lists that I am trying to partially apply and use with currying. The second parameter list contains arguments that all have default values (but not implicit). Something like this:

 def test(a: Int)(b: Int = 2, c: Int = 3) { println(a + ", " + b + ", " + c); }

Now, the following is all fine:

 test(1)(2, 3);
 test(1)(2);
 test(1)(c=3);
 test(1)();

Now if I define:

 def partial = test(1) _;

Then the following can be done:

 partial(2, 3);

Can someone explain why I can't omit some/all arguments in 'partial' as follows:

 partial(2);
 partial(c=3);
 partial();

Shouldn't writing "partial" behave essentially the same way as "test(1)"? Can someone please help me figure out a way to achieve this?

Please help, I'm desperate!

EDIT - Since I can't answer my own question within 24 hours, I'll post my own answer here:

This is the best I could do myself so far:

class Test2(val a: Int) {
   def apply(b: Int = 2, c: Int = 3) { println(a + ", " + b + ", " + c); }
}

def test2(a: Int) = new Test2(a);
def partial2 = test2(1); // Note no underscore

test2(1)(2, 3);
test2(1)(2);
test2(1)(c=3);
test2(1)();

partial2(2, 3)
partial2(2);
partial2(c=3);
partial2();

This way it works...

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

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

发布评论

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

评论(3

_蜘蛛 2024-11-08 04:31:00

类型推断引擎为 partial 提供接下来的类型;即 eta 扩展 test(1) _。例如,您可以在 REPL 中看到 partial 的类型为 (Int, Int) => Unit,而 test 的类型为 (a: Int)(b: Int,c: Int)Unit。 eta 扩展的结果是一个 Function 对象,它不带有任何参数名称(因为可以使用匿名参数定义 Function)。

要解决此问题,您必须按如下方式定义 partial

def partial(b: Int = 2, c: Int = 3) = test(1)(b,c)

也许您需要分解出 testpartial 都可以使用的默认值接触他们以确保他们保持平等。但我不知道有什么技巧可以避免重复参数名称而不引入额外的开销,例如创建新对象等。

The type inference engine gives to partial the type of what comes next; i.e., the eta expansion test(1) _. You can see e.g. in the REPL that partial has type (Int, Int) => Unit, whereas test has type (a: Int)(b: Int,c: Int)Unit. The result of the eta expansion is a Function object, which does not carry any argument names with it (as it is possible to define Function with anonymous parameters).

To fix this, you have to define partial as follows:

def partial(b: Int = 2, c: Int = 3) = test(1)(b,c)

Maybe you'll want to factor out the default values where both test and partial can reach them to make sure they stay equal. But I know of no trick to avoid repeating the names of the parameters without introducing extra overhead like creating of new objects, etc.

三岁铭 2024-11-08 04:31:00

这是迄今为止我自己能做的最好的事情:

class Test2(val a: Int) {
   def apply(b: Int = 2, c: Int = 3) { println(a + ", " + b + ", " + c); }
}

def test2(a: Int) = new Test2(a);
def partial2 = test2(1); // Note no underscore

test2(1)(2, 3);
test2(1)(2);
test2(1)(c=3);
test2(1)();

partial2(2, 3)
partial2(2);
partial2(c=3);
partial2();

这样就可以了......

This is the best I could do myself so far:

class Test2(val a: Int) {
   def apply(b: Int = 2, c: Int = 3) { println(a + ", " + b + ", " + c); }
}

def test2(a: Int) = new Test2(a);
def partial2 = test2(1); // Note no underscore

test2(1)(2, 3);
test2(1)(2);
test2(1)(c=3);
test2(1)();

partial2(2, 3)
partial2(2);
partial2(c=3);
partial2();

This way it works...

风向决定发型 2024-11-08 04:31:00

根据您的评论,这里有一种更紧凑的编写方式:

def test(a: Int) = new {
  def apply(b: Int = 2, c: Int = 3) {
    println(a + ", " + b + ", " + c)
  }
}

这比您的提案更紧凑,但效率较低,因为对内部 apply 的任何调用都将通过反射进行,如下所示与结构类型。实际上,test的返回类型是一个结构类型:

 java.lang.Object{def apply(b: Int,c: Int): Unit; def apply$default$1: 
 Int @scala.annotation.unchecked.uncheckedVariance; def apply$default$2: Int 
 @scala.annotation.unchecked.uncheckedVariance}

Following up on your comment, here's a more compact way to write it:

def test(a: Int) = new {
  def apply(b: Int = 2, c: Int = 3) {
    println(a + ", " + b + ", " + c)
  }
}

This is a bit more compact than your proposal, but is less efficient, as any call to the inner apply will occur through reflection, as with structural types. Actually, the return type of test is a structural type:

 java.lang.Object{def apply(b: Int,c: Int): Unit; def apply$default$1: 
 Int @scala.annotation.unchecked.uncheckedVariance; def apply$default$2: Int 
 @scala.annotation.unchecked.uncheckedVariance}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文