-
Notifications
You must be signed in to change notification settings - Fork 253
Created simple functional pattern matching construct. #45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a0754cb
0171338
6542ea3
190372c
9b4164f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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; | ||
|
|
||
| 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) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we be trying to make functions total and return |
||
| final List<Case<A, B>> cases = f.f(Unit.unit()); | ||
| final Option<Case<A, B>> option = cases.find(new F<Case<A, B>, Boolean>() { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use Java 8: |
||
| @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) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not return |
||
| return new Case<>(c, f); | ||
| } | ||
|
|
||
| public static <A, B> Case when(final Class<A> type, F<A, B> f) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would the signature be improved with: |
||
| 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) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. return |
||
| return new Case<>(new F<A, Boolean>() { | ||
| @Override | ||
| public Boolean f(A a) { | ||
| return true; | ||
| } | ||
| }, f); | ||
| } | ||
| } | ||
| 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; | ||
| } | ||
| }) | ||
| ); | ||
| } | ||
| }); | ||
| } | ||
| } |
| 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) | ||
| )); | ||
| } | ||
| } |
| 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) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| sbt.version=0.13.2 |
| 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") |
| 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" | ||
| ) |
There was a problem hiding this comment.
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>>?