Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b947a4f
Added int min, int max and ord monoid. Added FingerTree empty and in…
mperry Jun 2, 2016
6e5c822
Added show instances and toString implementations for finger trees
mperry Jun 2, 2016
45abb41
Test show on finger trees to expose what is going on inside the finge…
mperry Jun 2, 2016
8321b4f
Added streaming of finger trees
mperry Jun 3, 2016
a20a86e
Initial implementation of priority queue based on finger trees
mperry Jun 3, 2016
d630f99
Added priority queue show, toStream, toString. Fixed enqueue and deq…
mperry Jun 4, 2016
6bd372b
Added functional to PriorityQueue
mperry Jun 18, 2016
2a2b8ea
Added priority queue properties
mperry Jun 18, 2016
1a7f3e6
Added finger tree toStream property?
mperry Jun 18, 2016
efd0bfb
Merge branch 'master' into pqueue
mperry Jun 18, 2016
e0839e1
Merge in upstream changes to remove arbitrary wrapper
mperry Jun 18, 2016
e3d8fce
Added priority queue and related methods javadoc
mperry Jun 18, 2016
c9788d4
Make sorting a list stable
mperry Jun 18, 2016
72d980f
Added priority queue top N, equal to top, greater than top
mperry Jun 18, 2016
e5bc0e1
FIFO priority queue properties where the key is equal to the top key
mperry Jun 18, 2016
fc9f9bd
Added Ord.isLessThanOrEqualTo to Ord
mperry Jun 18, 2016
3718313
Added asserts, remove commented out and printlns from FingerTreeTest
mperry Jun 19, 2016
a506f06
Implemented suggestons from @jbgi for PriorityQueue
mperry Jun 19, 2016
d2bd8cb
Added F1Functions#dimap (profunctor pattern)
jbgi Jun 19, 2016
d1f24b3
avoid andThen indirection in F1 map and contramap
jbgi Jun 19, 2016
4351092
add an uncurried version of Function.apply for better perf.
jbgi Jun 19, 2016
0704e22
Ord: Take better advantage of the curried comparison function.
jbgi Jun 19, 2016
3812a83
Add uncons to FingerTree
jbgi Jun 19, 2016
f21c310
Add PriorityQueue.unqueue and use it to implement some other methods.
jbgi Jun 19, 2016
24703d5
Merge pull request #2 from jbgi/pqueue
mperry Jun 19, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions core/src/main/java/fj/F1Functions.java
Original file line number Diff line number Diff line change
Expand Up @@ -670,11 +670,18 @@ public static <A, B> ArrayList<B> mapJ(final F<A, B> f, final ArrayList<A> as) {
}

public static <A, B, C> F<A, C> map(F<A, B> target, F<B, C> f) {
return andThen(target, f);
return o(f, target);
}

public static <A, B, C> F<C, B> contramap(F<A, B> target, F<C, A> f) {
return andThen(f, target);
return o(target, f);
}

/**
* Both map (with g) and contramap (with f) the target function. (Profunctor pattern)
*/
public static <A, B, C, D> F<C, D> dimap(F<A, B> target, F<C, A> f, F<B, D> g) {
return c -> g.f(target.f(f.f(c)));
}

}
13 changes: 12 additions & 1 deletion core/src/main/java/fj/Function.java
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,18 @@ public static <A, B, C> F<C, B> bind(final F<C, A> ma, final F<A, F<C, B>> f) {
* @return A new function after applying the given higher-order function to the given function.
*/
public static <A, B, C> F<C, B> apply(final F<C, F<A, B>> cab, final F<C, A> ca) {
return bind(cab, f -> compose(f, ca));
return apply(uncurryF2(cab), ca);
}

/**
* Performs function application within a higher-order function (applicative functor pattern).
*
* @param cab The higher-order function to apply a function to.
* @param ca A function to apply within a higher-order function.
* @return A new function after applying the given higher-order function to the given function.
*/
public static <A, B, C> F<C, B> apply(final F2<C, A, B> cab, final F<C, A> ca) {
return c -> cab.f(c, ca.f(c));
}

/**
Expand Down
21 changes: 21 additions & 0 deletions core/src/main/java/fj/Monoid.java
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,16 @@ public static <A> Monoid<IO<A>> ioMonoid(final Monoid <A> ma) {
return monoid(Semigroup.ioSemigroup(ma.semigroup()), IOFunctions.unit(ma.zero()));
}

/**
* A monoid for the maximum of two integers.
*/
public static final Monoid<Integer> intMaxMonoid = monoid(Semigroup.intMaximumSemigroup, Integer.MIN_VALUE);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a use case for this? It is a valid instance but does not feel very mathematical as it rely on technicalities of integer representation limitations.
If I'm looking for a max value, I rarely want to default to Integer.MIN_VALUE: I prefer to be explicit about the default and use the semigroup.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using this monoid to annotate the nodes of the finger tree (the measured values) with integers and the max operation means the finger tree represents a priority queue.

The existing finger tree implementation uses a monoid to annotate the node, so I using it for that.


/**
* A monoid for the minimum of two integers.
*/
public static final Monoid<Integer> intMinMonoid = monoid(Semigroup.intMinimumSemigroup, Integer.MAX_VALUE);

/**
* A monoid for the Unit value.
*/
Expand All @@ -416,4 +426,15 @@ public static <A> Monoid<Set<A>> setMonoid(final Ord<A> o) {
return monoid(Semigroup.setSemigroup(), Set.empty(o));
}


/**
* A monoid for the maximum of elements with ordering o.
*
* @param o An ordering of elements.
* @param zero The minimum element.
*/
public static <A> Monoid<A> ordMaxMonoid(final Ord<A> o, final A zero) {
return monoid(o.max, zero);
}

}
118 changes: 46 additions & 72 deletions core/src/main/java/fj/Ord.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import java.math.BigInteger;
import java.util.Comparator;

import static fj.Function.apply;
import static fj.Function.compose;
import static fj.Function.curry;
import static fj.Semigroup.semigroup;

Expand All @@ -27,6 +29,8 @@ public final class Ord<A> {

private Ord(final F<A, F<A, Ordering>> f) {
this.f = f;
this.max = a1 -> apply((a2, o) -> o == Ordering.GT ? a1 : a2, f.f(a1));
this.min = a1 -> apply((a2, o) -> o == Ordering.LT ? a1 : a2, f.f(a1));
}

/**
Expand Down Expand Up @@ -66,7 +70,7 @@ public boolean eq(final A a1, final A a2) {
* @return An <code>Equal</code> for this order.
*/
public Equal<A> equal() {
return Equal.equal(curry(this::eq));
return Equal.equal(a -> compose(o -> o == Ordering.EQ, f.f(a)));
}

/**
Expand All @@ -92,6 +96,19 @@ public boolean isLessThan(final A a1, final A a2) {
return compare(a1, a2) == Ordering.LT;
}

/**
* Returns <code>true</code> if the first given argument is less than or equal to the second given argument,
* <code>false</code> otherwise.
*
* @param a1 An instance to compare for ordering to another.
* @param a2 An instance to compare for ordering to another.
* @return <code>true</code> if the first given argument is less than or equal to the second given argument,
* <code>false</code> otherwise.
*/
public boolean isLessThanOrEqualTo(final A a1, final A a2) {
return compare(a1, a2) != Ordering.GT;
}

/**
* Returns <code>true</code> if the first given argument is greater than the second given
* argument, <code>false</code> otherwise.
Expand All @@ -112,7 +129,7 @@ public boolean isGreaterThan(final A a1, final A a2) {
* @return A function that returns true if its argument is less than the argument to this method.
*/
public F<A, Boolean> isLessThan(final A a) {
return a2 -> compare(a2, a) == Ordering.LT;
return compose(o -> o != Ordering.LT, f.f(a));
}

/**
Expand All @@ -122,7 +139,7 @@ public F<A, Boolean> isLessThan(final A a) {
* @return A function that returns true if its argument is greater than the argument to this method.
*/
public F<A, Boolean> isGreaterThan(final A a) {
return a2 -> compare(a2, a) == Ordering.GT;
return compose(o -> o != Ordering.GT, f.f(a));
}

/**
Expand Down Expand Up @@ -151,19 +168,19 @@ public A min(final A a1, final A a2) {
/**
* A function that returns the greater of its two arguments.
*/
public final F<A, F<A, A>> max = curry(this::max);
public final F<A, F<A, A>> max;

/**
* A function that returns the lesser of its two arguments.
*/
public final F<A, F<A, A>> min = curry(this::min);
public final F<A, F<A, A>> min;

public final Semigroup<A> minSemigroup() {
return semigroup(this::min);
return semigroup(min);
}

public final Semigroup<A> maxSemigroup() {
return semigroup(this::max);
return semigroup(max);
}

public final Ord<A> reverse() { return ord(Function.flip(f)); }
Expand All @@ -181,92 +198,52 @@ public static <A> Ord<A> ord(final F<A, F<A, Ordering>> f) {
/**
* An order instance for the <code>boolean</code> type.
*/
public static final Ord<Boolean> booleanOrd = ord(
a1 -> a2 -> {
final int x = a1.compareTo(a2);
return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
});
public static final Ord<Boolean> booleanOrd = comparableOrd();

/**
* An order instance for the <code>byte</code> type.
*/
public static final Ord<Byte> byteOrd = ord(
a1 -> a2 -> {
final int x = a1.compareTo(a2);
return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
});
public static final Ord<Byte> byteOrd = comparableOrd();

/**
* An order instance for the <code>char</code> type.
*/
public static final Ord<Character> charOrd = ord(
a1 -> a2 -> {
final int x = a1.compareTo(a2);
return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
});
public static final Ord<Character> charOrd = comparableOrd();

/**
* An order instance for the <code>double</code> type.
*/
public static final Ord<Double> doubleOrd = ord(
a1 -> a2 -> {
final int x = a1.compareTo(a2);
return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
});
public static final Ord<Double> doubleOrd = comparableOrd();

/**
* An order instance for the <code>float</code> type.
*/
public static final Ord<Float> floatOrd = ord(
a1 -> a2 -> {
final int x = a1.compareTo(a2);
return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
});
public static final Ord<Float> floatOrd = comparableOrd();

/**
* An order instance for the <code>int</code> type.
*/
public static final Ord<Integer> intOrd = ord(
a1 -> a2 -> {
final int x = a1.compareTo(a2);
return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
});
public static final Ord<Integer> intOrd = comparableOrd();

/**
* An order instance for the <code>BigInteger</code> type.
*/
public static final Ord<BigInteger> bigintOrd = ord(
a1 -> a2 -> {
final int x = a1.compareTo(a2);
return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
});
public static final Ord<BigInteger> bigintOrd = comparableOrd();

/**
* An order instance for the <code>BigDecimal</code> type.
*/
public static final Ord<BigDecimal> bigdecimalOrd = ord(
a1 -> a2 -> {
final int x = a1.compareTo(a2);
return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
});
public static final Ord<BigDecimal> bigdecimalOrd = comparableOrd();

/**
* An order instance for the <code>long</code> type.
*/
public static final Ord<Long> longOrd = ord(
a1 -> a2 -> {
final int x = a1.compareTo(a2);
return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
});
public static final Ord<Long> longOrd = comparableOrd();

/**
* An order instance for the <code>short</code> type.
*/
public static final Ord<Short> shortOrd = ord(
a1 -> a2 -> {
final int x = a1.compareTo(a2);
return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
});
public static final Ord<Short> shortOrd = comparableOrd();

/**
* An order instance for the {@link Ordering} type.
Expand All @@ -284,23 +261,17 @@ public static <A> Ord<A> ord(final F<A, F<A, Ordering>> f) {
/**
* An order instance for the {@link String} type.
*/
public static final Ord<String> stringOrd = ord(
a1 -> a2 -> {
final int x = a1.compareTo(a2);
return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
});
public static final Ord<String> stringOrd = comparableOrd();

/**
* An order instance for the {@link StringBuffer} type.
*/
public static final Ord<StringBuffer> stringBufferOrd =
ord(a1 -> a2 -> stringOrd.compare(a1.toString(), a2.toString()));
public static final Ord<StringBuffer> stringBufferOrd = stringOrd.contramap(StringBuffer::toString);

/**
* An order instance for the {@link StringBuffer} type.
*/
public static final Ord<StringBuilder> stringBuilderOrd =
ord(a1 -> a2 -> stringOrd.compare(a1.toString(), a2.toString()));
public static final Ord<StringBuilder> stringBuilderOrd = stringOrd.contramap(StringBuilder::toString);

/**
* An order instance for the {@link Option} type.
Expand Down Expand Up @@ -514,9 +485,9 @@ public static <A extends Comparable<A>> Ord<A> comparableOrd() {
* @see #hashEqualsOrd()
*/
public static <A> Ord<A> hashOrd() {
return ord(a -> a2 -> {
final int x = a.hashCode() - a2.hashCode();
return x < 0 ? Ordering.LT : x == 0 ? Ordering.EQ : Ordering.GT;
return ord(a -> {
int aHash = a.hashCode();
return a2 -> Ordering.fromInt(Integer.compare(aHash, a2.hashCode()));
});
}

Expand All @@ -528,9 +499,12 @@ public static <A> Ord<A> hashOrd() {
* @return An order instance that is based on {@link Object#hashCode()} and {@link Object#equals}.
*/
public static <A> Ord<A> hashEqualsOrd() {
return ord(a -> a2 -> {
final int x = a.hashCode() - a2.hashCode();
return x < 0 ? Ordering.LT : x == 0 && a.equals(a2) ? Ordering.EQ : Ordering.GT;
return ord(a -> {
int aHash = a.hashCode();
return a2 -> {
final int a2Hash = a2.hashCode();
return aHash < a2Hash ? Ordering.LT : aHash == a2Hash && a.equals(a2) ? Ordering.EQ : Ordering.GT;
};
});
}

Expand Down
48 changes: 47 additions & 1 deletion core/src/main/java/fj/Show.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package fj;

import fj.data.*;
import fj.data.fingertrees.FingerTree;
import fj.data.fingertrees.Node;
import fj.data.hlist.HList;
import fj.data.vector.V2;
import fj.data.vector.V3;
Expand Down Expand Up @@ -301,6 +303,44 @@ public static <A> Show<Tree<A>> treeShow(final Show<A> sa) {
});
}

public static <V, A> Show<fj.data.fingertrees.Digit<V, A>> digitShow(final Show<V> sv, final Show<A> sa) {
return show(d -> {
String s = d.match(
o -> "One(" + o.measure() + " -> " + o.value() + ")",
two -> "Two(" + two.measure() + " -> " + v2Show(sa).showS(two.values()) + ")",
three -> "Three(" + three.measure() + " -> " + v3Show(sa).showS(three.values()) + ")",
four -> "Four(" + four.measure() + " -> " + v4Show(sa).showS(four.values()) + ")"
);
return Stream.fromString(s);
});
}

public static <V, A> Show<Node<V, A>> nodeShow(final Show<V> sv, final Show<A> sa) {
return show(n -> {
final String s = n.match(
n2 -> "Node2(" + n2.measure() + " -> " + v2Show(sa).showS(n2.toVector()) + ")",
n3 -> "Node3(" + n3.measure() + " -> " + v3Show(sa).showS(n3.toVector()) + ")");
return Stream.fromString(s);
});
}

public static <V, A> Show<FingerTree<V, A>> fingerTreeShow(final Show<V> sv, final Show<A> sa) {

return show(ft -> {
String sep = ", ";
String str = ft.match(e -> "Empty()",
s -> "Single(" + sv.showS(ft.measure()) + " -> " + sa.showS(s.value()) + ")",
d -> "Deep(" + d.measure() + " -> " +
digitShow(sv, sa).showS(d.prefix()) + sep +
fingerTreeShow(sv, nodeShow(sv, sa)).showS(d.middle()) + sep +
digitShow(sv, sa).showS(d.suffix()) +
")"
);
return Stream.fromString(str);
});
}


public static <A> Show<Seq<A>> seqShow(final Show<A> sa) {
return show(s -> streamShow(sa, "Seq(", ",", ")").show(s.toStream()));
}
Expand Down Expand Up @@ -337,7 +377,7 @@ public static <K, V> Show<TreeMap<K, V>> treeMapShow(final Show<K> sk, final Sho
* @return A show instance for the {@link P2 tuple-2} type.
*/
public static <A, B> Show<P2<A, B>> p2MapShow(final Show<A> sa, final Show<B> sb) {
return p2Show(sa, sb, "(", ":", ")");
return p2Show(sa, sb, "(", ": ", ")");
}

/**
Expand Down Expand Up @@ -550,6 +590,12 @@ public static <A, B, C, D, E> Show<P5<A, B, C, D, E>> p5Show(final Show<A> sa, f
.append(sg.show(p._7())).snoc(',').append(sh.show(p._8())).snoc(')'));
}

public static <K, V> Show<PriorityQueue<K, V>> priorityQueueShow(Show<K> sk, Show<V> sv) {
return show(pq -> {
return streamShow(p2MapShow(sk, sv), "PriorityQueue(", ", ", ")").show(pq.toStream());
});
}

/**
* A show instance for a vector-2.
*
Expand Down
Loading