[英]Collect arguments to apply to curried functions in Java/Scala
我想在Java 8中創建一個類,它能夠遞歸地創建一個對象,該對象具有一個方法,該方法根據我添加的參數獲取一個函數參數。
例如,我希望能夠這樣做:
new X().param(23).param("some String").param(someObject)
.apply((Integer a) -> (String b) -> (Object c) -> f(a,b,c))
然后,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
);
}
}
正如代碼注釋中所提到的,我的問題是按照param()調用的順序保存函數參數,並實際應用參數。
對於無限量的參數,我能想到的唯一解決方案是使用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
}
此代碼打印:
23Hello
65Hello
第二種,更有限的方法,可能與Java一起使用,是為每個函數長度創建多個類,它返回包含該值的下一個大小的函數長度類,直到某個最大長度 - 請參閱Applicative Builder in Scalaz: “Scalaz Applicative Builder”
這不能回答你的問題。 但是,也許它可以幫助某人找到解決方案,或解釋為什么在Java和/或Scala中不可能。
它可以在C ++中完成,具有任意數量的參數,並且不會丟失類型安全性。 呼叫方面看起來如下。 不幸的是,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';
};
};
});
以下是foo
和bar
的定義。 實施是直截了當的。 但是,我懷疑在Java中構建類似的東西是可能的,因為類型參數在Java中的工作方式。 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;
}
};
抱歉,我可以在Scala中提供一些線索:
也許有助於查看http://www.scala-lang.org/api/2.10.4/index.html#scala.Function $
.apply((Integer a) -> (String b) -> (Object c) -> f(a,b,c))
幾乎看起來像Function.uncurried
param(23).param("some String").param(someObject)
如果您不關心類型安全,可以使用累加器列表來實現。 如果你想保留類型,你可以使用無形的https://github.com/milessabin/shapeless的HList,它帶有一個方便的tuppled方法。
param()的實現:
import shapeless._
import HList._
import syntax.std.traversable._
class Method(val l : HList = HNil) {
def param(p: Any) = new Method( p :: l )
}
例
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.