[英]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);
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.