2014-04-21 23 views
9

Tôi muốn tạo một lớp trong Java 8 để có thể đệ quy tạo một đối tượng có phương thức lấy tham số hàm dựa trên các tham số tôi đã thêm vào.Thu thập các đối số để áp dụng cho các chức năng được thu thập trong Java/Scala

Ví dụ, tôi muốn để có thể làm điều này:

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

Phương pháp áp dụng sau đó sẽ áp dụng các thông số thu thập được để chức năng nhất định.

Tôi cảm thấy điều này có thể xảy ra mà không cần phản ánh trong khi duy trì an toàn loại, nhưng tôi không thể tìm ra cách thực hiện. Một giải pháp trong Scala cũng được hoan nghênh, nếu tôi có thể dịch nó sang Java 8. Nếu không thể, tôi cũng sẽ chấp nhận một câu trả lời giải thích tại sao.

Những gì tôi có cho đến nay về cơ bản là thế này:

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

Như đã đề cập trong các ý kiến ​​mã, vấn đề của tôi đang giữ các thông số chức năng theo thứ tự của các cuộc gọi của param(), và thực sự áp dụng các thông số .

+0

Có vẻ như bạn cần áp dụng. – pedrofurla

Trả lời

2

Đối với một số lượng không giới hạn các thông số, giải pháp duy nhất tôi có thể nghĩ đến là với Lists không đồng nhất trong Scala.

Có thể không khả thi trong Java vì có tính toán mức loại đang diễn ra với các kiểu phụ thuộc vào đường dẫn.

sử dụng danh sách không đồng nhất và các loại Path-phụ thuộc:

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 
} 

Mã này in:

23Hello 
65Hello 

Thứ hai, cách hạn chế hơn để làm điều này, nhưng mà có thể làm việc với Java, là để tạo nhiều lớp cho mỗi độ dài hàm, trả về lớp chiều dài hàm có kích thước tiếp theo, bao gồm giá trị, tối đa một số độ dài tối đa - Xem Trình tạo áp dụng trong Scalaz: "Scalaz Applicative Builder"

+0

khá thú vị, tôi có thể đi theo cách này nếu tôi quyết định ti thực hiện một cái gì đó tương tự trong Scala :) –

1

Điều này không trả lời câu hỏi của bạn. Tuy nhiên, có thể nó giúp ai đó tìm ra giải pháp, hoặc giải thích tại sao nó không thể có trong Java và/hoặc Scala.

Nó có thể được thực hiện bằng C++, với số lượng tham số tùy ý và không bị mất an toàn loại. Giao diện bên cuộc gọi như sau. Thật không may, cú pháp lambda trong C++ khá dài dòng.

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

Dưới đây là định nghĩa của foobar. Việc thực hiện là thẳng về phía trước. Tuy nhiên, tôi nghi ngờ rằng có thể xây dựng một cái gì đó như thế này trong Java, bởi vì các tham số kiểu cách làm việc trong Java. Bạn chỉ có thể sử dụng Generics trong Java để tránh loại phôi và điều đó không đủ cho trường hợp sử dụng này.

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

Xin lỗi tôi chỉ có thể đưa ra một số dẫn tại Scala:

Có lẽ nó sẽ giúp đỡ để có một cái nhìn tại http://www.scala-lang.org/api/2.10.4/index.html#scala.Function $

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

khá nhiều trông giống như Function.uncurried

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

có thể được triển khai bằng danh sách cho ắc quy nếu bạn không quan tâm đến an toàn Loại. Nếu bạn muốn giữ các loại bạn có thể sử dụng HList ra khỏi Shapeless https://github.com/milessabin/shapeless đi kèm với một phương pháp tuppled.

Thực hiện param():

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

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

Ví dụ

scala> val m = new Method().param(1).param("test") 
m: Method = [email protected] 

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

HList là một trong những suy nghĩ đầu tiên của tôi, nhưng shapeless không dễ dàng dịch sang Java :) Tôi muốn giữ các loại nếu có thể, nhưng tôi có thể giải quyết cho một hack. –

+0

Rất mong nhận được giải pháp của bạn. Điều này tất cả trông khá thú vị. –

Các vấn đề liên quan