收集参数以应用于Java/Scala中的curried函数

Jus*_*ser 10 java generics scala currying java-8

我想在Java 8中创建一个类,它能够递归地创建一个对象,该对象具有一个方法,该方法根据我添加的参数获取一个函数参数.

例如,我希望能够这样做:

new X().param(23).param("some String").param(someObject)
  .apply((Integer a) -> (String b) -> (Object c) -> f(a,b,c))
Run Code Online (Sandbox Code Playgroud)

然后,apply方法将收集的参数应用于给定的函数.

在维护类型安全的同时,我觉得这应该是没有反思的,但我无法弄清楚如何.如果我可以将其转换为Java 8,那么Scala中的解决方案也是受欢迎的.如果不可能,我也会接受解释原因的答案.

到目前为止我所拥有的基本上是这样的:

class ParamCmd<A,X> {

    final A param;

    public ParamCmd(A param) {
        this.param = param;
    }

    public<B> ParamCmd<B, Function<A,X>> param(B b) {
        return new ParamCmd<>(b);
    }

    public void apply(Function<A,X> f) {
        // this part is unclear to me
    }

    public static void main(String[] args) {
        new ParamCmd<Integer,String>(0).param("oops").param(new Object())
            // the constructed function parameters are reversed relative to declaration
            .apply((Object c) -> (String b) -> (Integer a) ->
                "args were " + a + " " + b + " " + c
            );
    }
}
Run Code Online (Sandbox Code Playgroud)

正如代码注释中所提到的,我的问题是按照param()调用的顺序保存函数参数,并实际应用参数.

Nig*_*tRa 2

对于无限数量的参数,我能想到的唯一解决方案是使用 Scala 中的异构列表。

这在 Java 中可能不可行,因为路径依赖类型正在进行类型级计算。

使用异构列表和路径相关类型:

import scala.language.higherKinds

object Main extends App {
  val builder1 = HCons(23, HCons("Hello", HNil))
  val builder2 = HCons(42L, builder1)

  val res1:String = builder1.apply(i => s => i + s)
  val res2:String = builder2.apply(l => i => s => (i+l) + s)
  println(res1) // 23Hello
  println(res2) // 65Hello
}

sealed trait HList {
  type F[Res]
  def apply[Res]: F[Res] => Res
}
case class HCons[Head, HTail <: HList](head: Head, tail: HTail) extends HList {
  type F[Res] = Head => (tail.type)#F[Res]
  def apply[Res]: F[Res] => Res = f => tail.apply(f(head))
}
case object HNil extends HList {
  type F[Res] = Res
  def apply[Res]: F[Res] => Res = identity
}
Run Code Online (Sandbox Code Playgroud)

此代码打印:

23Hello
65Hello
Run Code Online (Sandbox Code Playgroud)

第二种更有限的方法,但可能适用于 Java,是为每个函数长度创建多个类,它返回包装该值的下一个大小的函数长度类,直到某个最大长度 - 请参阅中的 Applicative Builder Scalaz:“Scalaz 应用生成器”