-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit c48a806
Showing
15 changed files
with
482 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.classpath | ||
.project | ||
.settings/ | ||
target/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<groupId>monad4j</groupId> | ||
<artifactId>monad4j-core</artifactId> | ||
<version>0.0.1-SNAPSHOT</version> | ||
<name>Monad4J</name> | ||
<description>implementation of monads in Java</description> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>junit</groupId> | ||
<artifactId>junit</artifactId> | ||
<version>4.8.1</version> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
<build> | ||
<pluginManagement> | ||
<plugins> | ||
<plugin> | ||
<artifactId>maven-compiler-plugin</artifactId> | ||
<version>2.3.2</version> | ||
<configuration> | ||
<source>1.7</source> | ||
<target>1.7</target> | ||
<debug>true</debug> | ||
<debuglevel>source,lines,vars</debuglevel> | ||
</configuration> | ||
</plugin> | ||
</plugins> | ||
</pluginManagement> | ||
</build> | ||
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package monad4j; | ||
|
||
public interface Function<A,R> { | ||
|
||
public R apply(A a); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package monad4j; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
@Target(ElementType.TYPE) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
public @interface InjectWith { | ||
@SuppressWarnings("rawtypes") | ||
Class<? extends Return> value(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package monad4j; | ||
|
||
public interface Monad<M, T> { | ||
|
||
public <RA, R extends Monad<M, RA>> R chain(Function<T, R> f); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package monad4j; | ||
|
||
/** | ||
* Static utility methods | ||
* | ||
* @author richard | ||
* | ||
*/ | ||
public class Monads { | ||
|
||
/** | ||
* In Haskell this is part of the type class, but here its a static method | ||
* | ||
*/ | ||
public static <T, W, M extends Monad<W, T>> M inject(T t, Class<W> cls) { | ||
InjectWith injectWith = cls.getAnnotation(InjectWith.class); | ||
if(injectWith == null) { | ||
throw new IllegalArgumentException("Don't know what class to inject "+cls.getName()+" with"); | ||
} | ||
|
||
try { | ||
@SuppressWarnings("unchecked") | ||
Return<T,M> injector = injectWith.value().newInstance(); | ||
|
||
return injector.inject(t); | ||
} catch (InstantiationException | IllegalAccessException e) { | ||
throw new IllegalStateException("Unable to create injector",e); | ||
} | ||
} | ||
|
||
/** | ||
* With JSR 335's default this could be in the monad interface (where it | ||
* should be). | ||
* | ||
* In Haskell: | ||
* | ||
* m >> f = m >>= \_ -> f | ||
*/ | ||
public static <A, RA, R extends Monad<M, RA>, M> R chainIgnore( | ||
Monad<M, A> m, final Function<Void, R> f) { | ||
return m.<RA, R> chain(new Function<A, R>() { | ||
@Override | ||
public R apply(A a) { | ||
return f.apply(null); | ||
} | ||
}); | ||
} | ||
|
||
/** | ||
* Promote a function to a monad. | ||
* | ||
* In Haskell: | ||
* | ||
* liftM f m = m >>= \x -> return (f x) | ||
*/ | ||
public static <M, R, A, RM extends Monad<M, R>, AM extends Monad<M, A>> Function<AM, RM> liftM( | ||
final Function<A, R> f) { | ||
return new Function<AM, RM>() { | ||
@Override | ||
public RM apply(final AM m) { | ||
return m.chain(new Function<A, RM>() { | ||
@Override | ||
public RM apply(A a) { | ||
// TODO: implement return | ||
return null; | ||
} | ||
}); | ||
} | ||
}; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package monad4j; | ||
|
||
/** | ||
* Corresponds to the 'unit function' of the Monad. In haskell this is called 'return', thus the naming. | ||
* | ||
* We have to represent this using an interface, since Java doesn't have function types | ||
* | ||
* @author richard | ||
* | ||
* @see Monads#inject(Object, Class) | ||
* | ||
*/ | ||
public interface Return<T, M extends Monad<?, T>> { | ||
|
||
public M inject(T t); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package monad4j.examples.maybe; | ||
|
||
import monad4j.Function; | ||
import monad4j.Monad; | ||
|
||
public class Just<T> extends Maybe<T> { | ||
|
||
private final T t; | ||
|
||
Just(T t) { | ||
this.t = t; | ||
} | ||
|
||
public T get() { | ||
return t; | ||
} | ||
|
||
@Override | ||
public void doCase(MaybeCase<T> visitor) { | ||
visitor.doJust(t); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
final int prime = 31; | ||
int result = 1; | ||
result = prime * result + ((t == null) ? 0 : t.hashCode()); | ||
return result; | ||
} | ||
|
||
@SuppressWarnings("rawtypes") | ||
@Override | ||
public boolean equals(Object obj) { | ||
if (this == obj) | ||
return true; | ||
if (obj == null) | ||
return false; | ||
if (getClass() != obj.getClass()) | ||
return false; | ||
Just other = (Just) obj; | ||
if (t == null) { | ||
if (other.t != null) | ||
return false; | ||
} else if (!t.equals(other.t)) | ||
return false; | ||
return true; | ||
} | ||
|
||
|
||
@Override | ||
public String toString() { | ||
return "Just "+t; | ||
} | ||
|
||
/** | ||
* Haskell Equivalent: | ||
* | ||
* (Just x) >>= k = k x | ||
*/ | ||
@SuppressWarnings("rawtypes") | ||
@Override | ||
public <RA, R extends Monad<Maybe, RA>> R chain(Function<T, R> f) { | ||
return f.apply(t); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package monad4j.examples.maybe; | ||
|
||
import monad4j.InjectWith; | ||
import monad4j.Monad; | ||
|
||
@SuppressWarnings("rawtypes") | ||
@InjectWith(MaybeReturn.class) | ||
public abstract class Maybe<T> implements Monad<Maybe, T> { | ||
|
||
public static <T> Maybe<T> nothing() { | ||
return new Nothing<T>(); | ||
} | ||
|
||
public static <T> Maybe<T> just(T t) { | ||
return new Just<T>(t); | ||
} | ||
|
||
public abstract void doCase(MaybeCase<T> visitor); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package monad4j.examples.maybe; | ||
|
||
public interface MaybeCase<T> { | ||
|
||
public void doJust(T t); | ||
|
||
public void doNothing(); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package monad4j.examples.maybe; | ||
|
||
import static monad4j.examples.maybe.Maybe.just; | ||
import monad4j.Return; | ||
|
||
/** | ||
* Haskell equivalent: | ||
* | ||
* return = Just | ||
*/ | ||
public class MaybeReturn<T> implements Return<T,Maybe<T>> { | ||
|
||
@Override | ||
public Maybe<T> inject(T t) { | ||
return just(t); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package monad4j.examples.maybe; | ||
|
||
import monad4j.Function; | ||
import monad4j.Monad; | ||
|
||
class Nothing<T> extends Maybe<T> { | ||
|
||
Nothing() { | ||
|
||
} | ||
|
||
@Override | ||
public void doCase(MaybeCase<T> visitor) { | ||
visitor.doNothing(); | ||
} | ||
|
||
@Override | ||
public boolean equals(Object obj) { | ||
return obj instanceof Nothing; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return super.hashCode(); | ||
} | ||
|
||
/** | ||
* Haskell equivalent: | ||
* | ||
* Nothing >>= _ = Nothing | ||
*/ | ||
|
||
@Override | ||
public String toString() { | ||
return "Nothing"; | ||
} | ||
|
||
@SuppressWarnings({ "unchecked", "rawtypes" }) | ||
@Override | ||
public <RA, R extends Monad<Maybe, RA>> R chain(Function<T, R> f) { | ||
return (R) Maybe.nothing(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package monad4j; | ||
|
||
import static junit.framework.Assert.assertEquals; | ||
import static monad4j.Monads.chainIgnore; | ||
import static monad4j.examples.maybe.Maybe.just; | ||
import static monad4j.examples.maybe.Maybe.nothing; | ||
import monad4j.Function; | ||
import monad4j.examples.maybe.Maybe; | ||
|
||
import org.junit.Test; | ||
|
||
public class TestMonads { | ||
|
||
Function<Void, Maybe<Integer>> f = new Function<Void, Maybe<Integer>>() { | ||
@Override | ||
public Maybe<Integer> apply(Void a) { | ||
return just(5); | ||
} | ||
}; | ||
|
||
@Test | ||
public void chainIgnoreNothing() { | ||
assertEquals(nothing(),chainIgnore(nothing(),f)); | ||
} | ||
|
||
@Test | ||
public void chainIgnoreJust() { | ||
assertEquals(just(5),chainIgnore(just(1),f)); | ||
} | ||
|
||
} |
Oops, something went wrong.