Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
51 changes: 51 additions & 0 deletions core/src/main/java/fj/data/Case.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package fj.data;

import fj.F;
import fj.Unit;

import static fj.Bottom.error;

public final class Case<A, B> {
private final F<A, Boolean> c;
private final F<A, B> f;

Copy link
Contributor

Choose a reason for hiding this comment

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

Did you consider a single function of type F<A, Option<P1<B>>?

public Case(F<A, Boolean> c, F<A, B> f) {
this.c = c;
this.f = f;
}

public static <A, B> B match(final A a, final F<Unit, List<Case<A, B>>> f) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we be trying to make functions total and return Option<B> here?

final List<Case<A, B>> cases = f.f(Unit.unit());
final Option<Case<A, B>> option = cases.find(new F<Case<A, B>, Boolean>() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Use Java 8:

cases.find(Case<A, B> that -> that.c.f(a))

@Override
public Boolean f(Case<A, B> that) {
return that.c.f(a);
}
});

if(option.isNone()) throw error("partial function unmatched");
else return option.some().f.f(a);
}

public static <A, B> Case when(F<A, Boolean> c, F<A, B> f) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not return Case<A, B> here?

return new Case<>(c, f);
}

public static <A, B> Case when(final Class<A> type, F<A, B> f) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Would the signature be improved with:
...<A extends C, B, C> Case<? extends C, B> when(F<A, B> f) { ...
I would need to fork the code and try this out.

return when(new F<A, Boolean>() {
@Override
public Boolean f(A o) {
return type.isInstance(o);
}
}, f);
}

public static <A, B> Case otherwise(F<A, B> f) {
Copy link
Contributor

Choose a reason for hiding this comment

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

return Case<A, B> here?

return new Case<>(new F<A, Boolean>() {
@Override
public Boolean f(A a) {
return true;
}
}, f);
}
}
184 changes: 184 additions & 0 deletions demo/src/main/java/fj/demo/PatternMatchingJava7.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package fj.demo;

import fj.*;
import fj.data.Case;
import fj.data.List;
import fj.data.Stream;

import static fj.P.p;
import static fj.Show.*;
import static fj.data.Case.*;
import static fj.data.List.list;
import static fj.data.Stream.fromString;
import static fj.data.Stream.join;

public class PatternMatchingJava7 {
public static void main(String[] args) {
List<Leaf> leafs = makeOrderedLeafList(list(p('x', 8), p('y', 3)));
leafs.foreach(new Effect<Leaf>() {
@Override
public void e(Leaf leaf) {
leafShow.println(leaf);
}
});
CodeTree codeTree = makeCodeTree(leafs.head(), leafs.tail().head());
codeTreeShow.println(codeTree);
}

static abstract class CodeTree {

}

static final class Fork extends CodeTree {
public final CodeTree left;
public final CodeTree right;
public final List<Character> chars;
public final Integer weight;

public Fork(CodeTree left, CodeTree right, List<Character> chars, Integer weight) {
this.left = left;
this.right = right;
this.chars = chars;
this.weight = weight;
}
}

static final class Leaf extends CodeTree {
public final Character character;
public final Integer weight;

public Leaf(Character character, Integer weight) {
this.character = character;
this.weight = weight;
}
}

public static final Show<CodeTree> codeTreeShow = Show.show(new F<CodeTree, Stream<Character>>() {
@Override
public Stream<Character> f(CodeTree codeTree) {
return match(codeTree, new F<Unit, List<Case<CodeTree, Stream<Character>>>>() {
@Override
public List<Case<CodeTree, Stream<Character>>> f(Unit unit) {
return List.<Case<CodeTree, Stream<Character>>>list(
when(Fork.class, new F<Fork, Stream<Character>>() {
@Override
public Stream<Character> f(Fork fork) {
return forkShow.show(fork);
}
}),
when(Leaf.class, new F<Leaf, Stream<Character>>() {
@Override
public Stream<Character> f(Leaf leaf) {
return leafShow.show(leaf);
}
})
);
}
});
}
});
public static final Show<Leaf> leafShow = Show.show(new F<Leaf, Stream<Character>>() {
@Override
public Stream<Character> f(Leaf leaf) {
return Stream.fromString("Leaf('").
append(charShow.show(leaf.character)).
append(Stream.fromString("', ")).
append(intShow.show(leaf.weight)).
append(Stream.fromString(")"));
}
});
public static final Show<Fork> forkShow = Show.show(new F<Fork, Stream<Character>>() {
@Override
public Stream<Character> f(Fork fork) {
return Stream.fromString("Fork(").
append(codeTreeShow.show(fork.left)).
append(Stream.fromString(", ")).
append(codeTreeShow.show(fork.right)).
append(Stream.fromString(", ")).
append(join(fork.chars.
toStream().
map(charShow.show_()).
intersperse(fromString("', '")).
cons(fromString("List('")).
snoc(p(fromString("')"))))).
append(Stream.fromString(", ")).
append(intShow.show(fork.weight)).
append(Stream.fromString(")"));
}
});

public static List<Character> chars(CodeTree tree) {
return match(tree, new F<Unit, List<Case<CodeTree, List<Character>>>>() {
@Override
public List<Case<CodeTree, List<Character>>> f(Unit unit) {
return List.<Case<CodeTree, List<Character>>>list(
when(Fork.class, new F<Fork, Object>() {
@Override
public List<Character> f(Fork fork) {
return chars(fork.left).append(chars(fork.right));
}
}),
when(Leaf.class, new F<Leaf, List<Character>>() {
@Override
public List<Character> f(Leaf leaf) {
return List.<Character>list(leaf.character);
}
})
);
}
});
}

public static CodeTree makeCodeTree(CodeTree left, CodeTree right) {
return new Fork(left, right, chars(left).append(chars(right)), weight(left) + weight(right));
}

public static List<Leaf> makeOrderedLeafList(List<P2<Character, Integer>> freqs) {
return match(freqs, new F<Unit, List<Case<List<P2<Character, Integer>>, List<Leaf>>>>() {
@Override
public List<Case<List<P2<Character, Integer>>, List<Leaf>>> f(Unit unit) {
return List.<Case<List<P2<Character, Integer>>, List<Leaf>>>list(
when(new F<List, Boolean>() {
@Override
public Boolean f(List xs) {
return xs.isEmpty();
}
}, new F<List, List<Leaf>>() {
@Override
public List<Leaf> f(List ys) {
return List.<Leaf>nil();
}
}),
otherwise(new F<List<P2<Character, Integer>>, List<Leaf>>() {
@Override
public List<Leaf> f(List<P2<Character, Integer>> ys) {
return List.<Leaf>cons(new Leaf(ys.head()._1(), ys.head()._2()), makeOrderedLeafList(ys.tail()));
}
})
);
}
});
}

public static Integer weight(CodeTree tree) {
return match(tree, new F<Unit, List<Case<CodeTree, Integer>>>() {
@Override
public List<Case<CodeTree, Integer>> f(Unit unit) {
return List.<Case<CodeTree, Integer>>list(
when(Fork.class, new F<Fork, Integer>() {
@Override
public Integer f(Fork fork) {
return weight(fork.left) + weight(fork.right);
}
}),
when(Leaf.class, new F<Leaf, Integer>() {
@Override
public Integer f(Leaf leaf) {
return leaf.weight;
}
})
);
}
});
}
}
117 changes: 117 additions & 0 deletions demo/src/main/java/fj/demo/PatternMatchingJava8.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package fj.demo;

import fj.*;
import fj.data.Case;
import fj.data.List;
import fj.data.Stream;

import static fj.P.p;
import static fj.Show.charShow;
import static fj.Show.intShow;
import static fj.data.Case.*;
import static fj.data.List.cons;
import static fj.data.List.list;
import static fj.data.Stream.fromString;
import static fj.data.Stream.join;

public class PatternMatchingJava8 {
public static void main(String[] args) {
List<Leaf> leafs = makeOrderedLeafList(list(p('x', 8), p('y', 3)));
leafs.foreach(leafShow::println);
CodeTree codeTree = makeCodeTree(leafs.head(), leafs.tail().head());
codeTreeShow.println(codeTree);
}

static abstract class CodeTree {

}

static final class Fork extends CodeTree {
public final CodeTree left;
public final CodeTree right;
public final List<Character> chars;
public final Integer weight;

public Fork(CodeTree left, CodeTree right, List<Character> chars, Integer weight) {
this.left = left;
this.right = right;
this.chars = chars;
this.weight = weight;
}
}

static final class Leaf extends CodeTree {
public final Character character;
public final Integer weight;

public Leaf(Character character, Integer weight) {
this.character = character;
this.weight = weight;
}
}

public static final Show<CodeTree> codeTreeShow = Show.show(new F<CodeTree, Stream<Character>>() {
@Override
public Stream<Character> f(CodeTree codeTree) {
return match(codeTree, unit -> list(
when(Fork.class, fork -> forkShow.show(fork)),
when(Leaf.class, leaf -> leafShow.show(leaf))
));
}
});
public static final Show<Leaf> leafShow = Show.show(new F<Leaf, Stream<Character>>() {
@Override
public Stream<Character> f(Leaf leaf) {
return Stream.fromString("Leaf('").
append(charShow.show(leaf.character)).
append(Stream.fromString("', ")).
append(intShow.show(leaf.weight)).
append(Stream.fromString(")"));
}
});
public static final Show<Fork> forkShow = Show.show(new F<Fork, Stream<Character>>() {
@Override
public Stream<Character> f(Fork fork) {
return Stream.fromString("Fork(").
append(codeTreeShow.show(fork.left)).
append(Stream.fromString(", ")).
append(codeTreeShow.show(fork.right)).
append(Stream.fromString(", ")).
append(join(fork.chars.
toStream().
map(charShow.show_()).
intersperse(fromString("', '")).
cons(fromString("List('")).
snoc(p(fromString("')"))))).
append(Stream.fromString(", ")).
append(intShow.show(fork.weight)).
append(Stream.fromString(")"));
}
});

public static List<Character> chars(CodeTree tree) {
return (List<Character>) match(tree, unit -> List.<Case<CodeTree, List<Character>>>list(
when(Fork.class, fork -> chars(fork.left).append(chars(fork.right))),
when(Leaf.class, leaf -> List.<Character>list(leaf.character))
));
}

public static CodeTree makeCodeTree(CodeTree left, CodeTree right) {
return new Fork(left, right, chars(left).append(chars(right)), weight(left) + weight(right));
}

public static List<Leaf> makeOrderedLeafList(List<P2<Character, Integer>> freqs) {
return (List<Leaf>) match(freqs, unit -> List.<Case<List<P2<Character, Integer>>, List<Leaf>>>list(
when((F<List, Boolean>) List::isEmpty, ys -> List.<Leaf>nil()),
otherwise((List<P2<Character, Integer>> ys) ->
cons(new Leaf(ys.head()._1(), ys.head()._2()), makeOrderedLeafList(ys.tail())))
));
}

public static Integer weight(CodeTree tree) {
return (Integer) match(tree, unit -> List.<Case<CodeTree, Integer>>list(
when(Fork.class, fork -> weight(fork.left) + weight(fork.right)),
when(Leaf.class, leaf -> leaf.weight)
));
}
}
21 changes: 21 additions & 0 deletions project/Build.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import sbt._
import sbt.Keys._

object Build extends sbt.Build {
override val settings = super.settings ++ Seq(
name := "functionaljava",
version := "4.1-SNAPSHOT",
organization := "org.functionaljava",
scalaVersion := "2.10.4",
scalacOptions += "-target:jvm-1.7",
javacOptions ++= Seq("-source", "1.8", "-target", "1.8")
)

lazy val core = Project(id = "core", base = file("core"), settings = settings ++ Project.defaultSettings)

lazy val demo = Project(id = "demo", base = file("demo"), settings = settings ++ Project.defaultSettings) dependsOn core

lazy val tests = Project(id = "tests", base = file("tests"), settings = settings ++ Project.defaultSettings) dependsOn core

lazy val root = Project(id = "functionaljava", base = file("."), settings = settings ++ Project.defaultSettings) aggregate(core, demo)
}
1 change: 1 addition & 0 deletions project/build.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sbt.version=0.13.2
7 changes: 7 additions & 0 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
logLevel := Level.Warn

addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.6.0")

addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.5.0")

addSbtPlugin("com.orrsella" % "sbt-sublime" % "1.0.9")
6 changes: 6 additions & 0 deletions tests/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
libraryDependencies ++= Seq(
"org.slf4j" % "slf4j-api" % "1.7.5",
"org.scalacheck" %% "scalacheck" % "1.10.0" % "test",
"org.scalatest" %% "scalatest" % "1.9.2" % "test",
"junit" % "junit" % "4.11" % "test"
)