Получить аргументы из частично примененной функции в Scala - PullRequest
1 голос
/ 16 марта 2011

Есть ли в scala способ вернуть аргументы из уже частично примененной функции?

Имеет ли это смысл, должно быть сделано или вписывается в любой вариант использования?

пример:

def doStuff(lower:Int,upper:Int,b:String)= for(turn <- lower to upper) println(turn +": "+b)

Представьте себе, что в какой-то момент я знаю аргумент 'lower' и получаю функцию применения его к 'doStuff'

val lowerDoStuff = doStuff(3,_:Int,_:String)

Есть ли способ вернуть мне эти 3? (для примера, представьте, что я нахожусь внутри функции, которая получила только 'lowerDoStuff' и теперь должна знать первый аргумент)

Идиоматическая скала предпочтительнее, чем самоанализ / рефлексия (если это возможно).

1 Ответ

7 голосов
/ 16 марта 2011

Идиоматическая Скала: нет, вы не можете. Вы специально сказали, что первый аргумент уже не актуален. Если компилятор может заставить его полностью исчезнуть, это лучше: вы говорите, что у вас есть функция, которая зависит от типа int и строки, и вы не дали никаких обещаний относительно того, что сгенерировало ее. Если вам действительно нужно это значение, но вам также необходимо передать функцию с двумя аргументами, вы можете сделать это вручную:

class Function2From3[A,B,C,Z](f: (A,B,C) => Z, val _1: A) extends Function2[B,C,Z] {
  def apply(b: B, c: C) = f(_1, b, c)
}
val lowerDoStuff = new Function2From3(doStuff _, 3)

Теперь, когда вы получите функцию позже, вы можете выполнить сопоставление с образцом, чтобы увидеть, является ли она Function2From3, а затем прочитать значение:

val f: Function2[Int,String,Unit] = lowerDoStuff
f match {
  case g: Function2From3[_,_,_,_] => println("I know there's a "+g._1+" in there!")
  case _ => println("It's all Greek to me.")
}

(если для вас важно, чтобы это было целое число, вы можете удалить A в качестве универсального параметра и сделать _1 целым числом - и, возможно, просто вызвать его lower, пока вы в нем) .

Отражение: нет, вы не можете (не в целом). Компилятор умнее этого. Сгенерированный байт-код (если мы заключим ваш код в class FuncApp):

public final void apply(int, java.lang.String);
  Signature: (ILjava/lang/String;)V
  Code:
   0:   aload_0
   1:   getfield    #18; //Field $outer:LFuncApp;
   4:   iconst_3
   5:   iload_1
   6:   aload_2
   7:   invokevirtual   #24; //Method FuncApp.doStuff:(IILjava/lang/String;)V
   10:  return

Обратите внимание на iconst_3? Вот куда ушли ваши 3 - они исчезли в байт-код. Там даже нет скрытого частного поля, содержащего значение.

...