10

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

 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();

这样就可以了...

4

3 回答 3

6

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

要解决此问题,您必须定义partial如下:

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

也许您会想将两者的默认值分解testpartial可以达到它们以确保它们保持相等。但我不知道避免重复参数名称而不引入额外开销(如创建新对象等)的技巧。

于 2011-04-15T12:05:35.127 回答
4

到目前为止,这是我自己能做到的最好的:

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();

这样就可以了...

于 2011-04-16T16:03:58.890 回答
2

跟进您的评论,这是一种更紧凑的编写方式:

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}
于 2011-04-15T14:12:32.420 回答