簡體   English   中英

Java作為通用的高級函數式編程語言

[英]Java as generic higher-order functional programming language

我正在解決算法問題,我想編寫可應用於集合的自定義函數和謂詞。 最近,我開始使用Google收藏夾,這對於完成這項任務來說真是太好了。

我想以相同的方式使用BigInteger和BigDecimal,就像我將使用任何其他數字一樣。 在不考慮應該怎么做的情況下,我決定增加一個額外的抽象層(E類)。

如果不清楚我要做什么,可以舉一個例子:

I.range(1,999).multiplication(I.range(1,999)).palindromes().max().echo(2); 
  1. 返回序列1:999的集合(x2)
  2. 使用times()轉換方法返回每個項目2個集合
  3. 返回通過回文過濾器的每個項目的集合
  4. 返回3的最大元素E <?>
  5. 返回元素E <?>並調用基數為2(二進制)的toString方法並將其打印到屏幕上

E類定義為:

public class E<T extends Number & Comparable<? super T>> extends Number implements Comparable<E<T>> {//...

C類定義為:

public class C<T extends E<NC>, NC extends Number & Comparable<? super NC>> implements Collection<T> {

這就是我要在C類中進行的工作。

 public Collection<T> multiplication(T value) {
  return Collections2.transform(this, new Function<T, T>() {
   @Override
   public T apply(T in) {
    return in.times(value);
   }
  });
 }

在我使用以下代碼之前,在E類中

 /** Multiplies 2 numbers */
 public E<?> times(E<?> elem) {
  if (this.value == null || elem.value == null) return E.Null();
  if (this.value instanceof Integer) {
   return E.with(I, this.intValue() * elem.intValue());
  } else if (this.value instanceof Long) {
   return E.with(L, this.longValue() * elem.longValue());
  } else if (this.value instanceof Float) {
   return E.with(F, this.floatValue() * elem.floatValue());
  } else if (this.value instanceof Double) {
   return E.with(D, this.doubleValue() * elem.doubleValue());
  } else if (this.value instanceof BigInteger) {
   return E.with(BI, this.BigIntegerValue().multiply(
    elem.BigIntegerValue()));
  } else if (this.value instanceof BigDecimal) { return E.with(BD,
   this.BigDecimalValue().multiply(elem.BigDecimalValue())); }

  return E.Null();
 }

我應該改變什么,以便編寫自定義函數和謂詞將涉及最少的“麻煩”

編輯:

好吧,將C更改為:

public class C<T extends E<?>> extends ArrayList<T> {

只是取消了通用通配符轉換警告,例如

public Collection<T> multiplication(Collection<T> value) {
    C<T> result = new C<T>();

    for (T t : value)
        result.addAll(multiplication(t));
    return result;
}

public Collection<T> multiplication(final T value) {
    return Collections2.transform(this, new Function<T, T>() {
        @SuppressWarnings("unchecked")
        @Override
        public T apply(T in) {
            return (T) in.times(value);
        }
    });
}

因此,如果類型匹配,則可行。

可以使用Scala嗎?

它是一種可以在jdk下運行的功能性編程語言。

您可以使用Functional Java庫。

package euler;

import fj.F;
import static fj.Function.flip;
import fj.data.Stream;
import static fj.data.Stream.range;
import static fj.function.Integers.multiply;
import static fj.function.Integers.add;
import static fj.pre.Equal.charEqual;
import static fj.pre.Equal.streamEqual;
import static fj.pre.Ord.intOrd;
import static fj.pre.Show.intShow;

/**
 * Find the largest palindrome made from the product of two 3-digit numbers.
 */
public class Problem4
  {private static final F<Integer, Boolean> palindrome =
    new F<Integer, Boolean>() {public Boolean f(final Integer i)
      {final Stream<Character> s = intShow.show(i);
       return streamEqual(charEqual).eq(s.reverse(), s);}}

   public static void main(final String[] a)
     {final Stream<Integer> xs = range(100, 999);
      intShow.println(xs.tails().bind(xs.zipWith(multiply)).filter(palindrome)
                      .foldLeft1(intOrd.max));}}

編輯 ,下面是使用噪音過濾眼鏡的外觀:

palindrome i = s == reverse s
  where s = show i

main = putStrLn . maximum . filter palindrome $ tails xs >>= zipWith (*) xs
  where xs = [100..999]

盡管我同意這不是Java的小巷,但解決此問題的一種方法可能是初始化Map,如下所示:

  public interface Multiply<T> {
        T multiply(T one, T two);
  }


   //In some initializaiton code, say a static initializer

   Map<Class<?>, Multiply<?>> map = newHashMap(); //That is the method from Google Collections
   map.put(Integer.class, new Multiply<Integer>(){
        Integer multiply(Integer one, Integer two) {
            return one * two;
        }
   });

等等。 然后在您的代碼中(進行適當的null檢查):

  Multiply mult = map.get(this.value.getClass());
  Object val = mult.multiply(this.value, elem.value));

注意,這里的原始類型是有目的的,我必須考慮是否可以做到這一點,並使所有內容保持通用。 無論如何,都不容易。

但是給定val的類別,您可以檢索適當的E。

這不是完全超出我的腦海,所以我還沒有測試一些潛在的通用陷阱。

您可以使用反射。 根據類的名稱,找到方法並調用它。 例如,對於“ BigInteger”,您稱為“ BigIntegerValue”,依此類推。

在Java中處理不同的原始類型非常煩人,我不確定是否可以輕松實現。 您可能會失敗幾次,直到正確為止。 也許您可以創建一個通用的Number類,以抽象出大小(如int,long,short等)和類型(整數,十進制等)之間的差異,就像語言(例如Ruby,Smalltalk)一樣。 根據結果​​的結果,您可以切換內部表示。 例如,如果整數運算溢出,則切換到long。 或者,如果在操作中使用浮點數,則切換為內部浮點數。 但是從外面看,這只是一個數字。 這將使其余課程的學習變得容易。

換句話說,您可以編寫一個代碼生成器來為您編寫所有這些煩人的案例。 它不應該太復雜。

我相信Scala可能是解決您問題的最佳解決方案。

相反,如果您必須使用Java,請訪問http://code.google.com/p/lambdaj/並訪問lambdaj。

您會發現,所需的最大部分已經在此處實現。

Clojure是在jvm上運行的類似lisp的功能語言。 它具有傳統的無類型lisp語義的bignums,ratios和bigdecimals。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM