简体   繁体   English

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

[英]Collect arguments to apply to curried functions in Java/Scala

I would like to create a class in Java 8 which is able to recursively create an object which has a method that takes a function parameter based on the parameters I added. 我想在Java 8中创建一个类,它能够递归地创建一个对象,该对象具有一个方法,该方法根据我添加的参数获取一个函数参数。

For example, I would like to be able to do this: 例如,我希望能够这样做:

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

The apply method would then apply the collected parameters to the given function. 然后,apply方法将收集的参数应用于给定的函数。

I feel this should be possible without reflection while maintaing type-safety, but I can't quite figure out how. 在维护类型安全的同时,我觉得这应该是没有反思的,但我无法弄清楚如何。 A solution in Scala is also welcome, if I can translate it to Java 8. If it's not possible, I'll also accept an answer that explains why. 如果我可以将其转换为Java 8,那么Scala中的解决方案也是受欢迎的。如果不可能,我也会接受一个解释原因的答案。

What I have so far is essentially this: 到目前为止我所拥有的基本上是这样的:

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

As noted in the code comments, my problems are keeping the function parameters in the order of the calls of param(), and actually applying the parameters. 正如代码注释中所提到的,我的问题是按照param()调用的顺序保存函数参数,并实际应用参数。

For an unlimited amount of parameters, the only solution I could think of is with Heterogeneous Lists in Scala. 对于无限量的参数,我能想到的唯一解决方案是使用Scala中的异构列表。

It is probably isn't feasible in Java as there is type level computation going on with path-dependant types. 它可能在Java中不可行,因为存在类型级计算与路径依赖类型。

Using Heterogeneous Lists and Path-Dependant types: 使用异构列表和路径依赖类型:

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
}

This code prints: 此代码打印:

23Hello
65Hello

The second, more limited way of doing this, but which might work with Java, is to create multiple classes for each function length, which returns the next sized function length class wrapping the value, up to some maximal length - See the Applicative Builder in Scalaz: "Scalaz Applicative Builder" 第二种,更有限的方法,可能与Java一起使用,是为每个函数长度创建多个类,它返回包含该值的下一个大小的函数长度类,直到某个最大长度 - 请参阅Applicative Builder in Scalaz: “Scalaz Applicative Builder”

This doesn't answer your question. 这不能回答你的问题。 However, maybe it helps someone to find a solution, or to explain why it isn't possible in Java and/or Scala. 但是,也许它可以帮助某人找到解决方案,或解释为什么在Java和/或Scala中不可能。

It can be done in C++, with an arbitrary number of parameters, and without losing type-safety. 它可以在C ++中完成,具有任意数量的参数,并且不会丢失类型安全性。 The call-side look as follows. 呼叫方面看起来如下。 Unfortunately, the lambda syntax in C++ is quite verbose. 不幸的是,C ++中的lambda语法非常冗长。

bar{}.param(23).param("some String").param(4.2).apply(
    [](int i) {
        return [=](std::string s) {
            return [=](double d) {
                std::cout << i << ' ' << s << ' ' << d << '\n';
            };
        };
    });

Following is the definition of foo and bar . 以下是foobar的定义。 The implementation is straight-forward. 实施是直截了当的。 However, I doubt that it is possible to build something like this in Java, because the way type parameters work in Java. 但是,我怀疑在Java中构建类似的东西是可能的,因为类型参数在Java中的工作方式。 Generics in Java can only be used to avoid type casts , and that's not enough for this use case. Java中的泛型只能用于避免类型转换 ,这对于这个用例来说还不够。

template <typename Param, typename Tail>
struct foo {
    Param _param;
    Tail _tail;
    template <typename P>
    auto param(P p) {
        return foo<P, foo>{p, *this};
    }
    template <typename Function>
    auto apply(Function function) {
        return _tail.apply(function)(_param);
    }
};

struct bar {
    template <typename P>
    auto param(P p) {
        return foo<P, bar>{p, *this};
    }
    template <typename Function>
    auto apply(Function function) {
        return function;
    }
};

Sorry I just could give some leads in Scala: 抱歉,我可以在Scala中提供一些线索:

Perhaps it would help to have a look at http://www.scala-lang.org/api/2.10.4/index.html#scala.Function $ 也许有助于查看http://www.scala-lang.org/api/2.10.4/index.html#scala.Function $

.apply((Integer a) -> (String b) -> (Object c) -> f(a,b,c))

pretty much looks like Function.uncurried 几乎看起来像Function.uncurried

param(23).param("some String").param(someObject)

could be implemented using a list for an accumulator if you don't care for Type safety. 如果您不关心类型安全,可以使用累加器列表来实现。 If you want to keep the Types you could use the HList out of Shapeless https://github.com/milessabin/shapeless which comes with a handy tuppled method. 如果你想保留类型,你可以使用无形的https://github.com/milessabin/shapeless的HList,它带有一个方便的tuppled方法。

Implementation of param(): param()的实现:

import shapeless._
import HList._
import syntax.std.traversable._

class Method(val l : HList = HNil) {
  def param(p: Any) = new Method( p :: l )
}

Example

scala> val m = new Method().param(1).param("test")
m: Method = Method@1130ad00

scala> m.l
res8: shapeless.HList = test :: 1 :: HNil

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM