Last active
August 29, 2015 14:08
-
-
Save uehaj/5d88051646f8e1a6b12f to your computer and use it in GitHub Desktop.
TypeClass for groovy
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
import java.util.function.* | |
import groovy.transform.TypeChecked | |
import static Util.* | |
/* Type Classes */ | |
@TypeChecked | |
interface Semigroup<T> { | |
def T mappend(T t1, T t2); | |
} | |
@TypeChecked | |
interface Monoid<T> extends Semigroup<T> { | |
def T mempty(); | |
} | |
@TypeChecked | |
class ListMonoid implements Monoid<List> { | |
@Override | |
public List mappend(List i1, List i2) { | |
i1+i2 as List | |
} | |
@Override | |
public List mempty() { | |
[] | |
} | |
} | |
@TypeChecked | |
class OptionalMonoid<T> implements Monoid<Optional<T>> { | |
Monoid<T> elemMonoidDict | |
OptionalMonoid(/*@Implicit*/ Monoid<T> monoidDict) { | |
this.elemMonoidDict = monoidDict | |
} | |
@Override | |
public Optional<T> mappend(Optional<T> i1, Optional<T> i2) { | |
if (i1.isPresent() && !i2.isPresent()) { | |
return i1 | |
} | |
else if (!i1.isPresent() && i2.isPresent()) { | |
return i2 | |
} | |
else if (!i1.isPresent() && !i2.isPresent()) { | |
return Optional.empty() | |
} | |
return Optional.of(elemMonoidDict.mappend(i1.get(), i2.get())) | |
} | |
@Override | |
public Optional<T> mempty() { | |
Optional.empty() | |
} | |
} | |
@TypeChecked | |
interface Functor<F> { | |
public <T,R> F<R> fmap(Function<T,R> func, F<T> t) // fmap :: (a -> b) -> f a -> f b | |
} | |
@TypeChecked | |
class ListFunctor implements Functor<List> { | |
@Override | |
public <T,R> List<R> fmap(Function<T,R> func, List<T> t) { | |
t.collect { func.apply(it) } | |
} | |
} | |
@TypeChecked | |
class OptionalFunctor implements Functor<Optional> { | |
@Override | |
public <T,R> Optional<R> fmap(Function<T,R> func, Optional<T> t) { | |
if (t.isPresent()) { | |
return Optional.ofNullable(func.apply(t.get())) | |
} | |
else { | |
return Optional.empty() | |
} | |
} | |
} | |
@TypeChecked | |
interface Applicative<A> extends Functor<A> { | |
public <T> A<T> pure(T t) | |
public <T,R> A<R> ap(A<Function<T,R>> func, A<T> a) // <*> :: f (a -> b) -> f a -> f b | |
} | |
@TypeChecked | |
interface Monad<M> extends Applicative<M> { | |
public <T,R> M<T> unit(T t) | |
public <T,R> M<R> bind(M<T> a, Function<T,M<R>> func) // (>>=) :: m a -> (a -> m b) -> m b | |
} | |
@TypeChecked | |
interface Show<T> { | |
String show(T t) | |
} | |
@TypeChecked | |
trait Eq<T> { // One of eq or neq, or both should be overriden. | |
boolean eq(T t1, T t2) { | |
!neq(t1, t2) | |
} | |
boolean neq(T t1, T t2) { | |
!eq(t1, t2) | |
} | |
} | |
@TypeChecked | |
trait Ord<T> extends Eq<T> { | |
boolean gt(T t1, T t2) { | |
!eq(t1,t2) && !lt(t1, t2) | |
} | |
boolean lt(T t1, T t2) { | |
!eq(t1,t2) && !gt(t1, t2) | |
} | |
boolean ge(T t1, T t2) { | |
eq(t1,t2) || gt(t1, t2) | |
} | |
boolean le(T t1, T t2) { | |
eq(t1,t2) || lt(t1, t2) | |
} | |
} | |
/* instance declarations */ | |
@TypeChecked | |
class Sum implements Monoid<Number> { | |
@Override | |
def Number mappend(Number i1, Number i2) { | |
i1+i2 | |
} | |
@Override | |
def Number mempty() { | |
new Integer(0) | |
} | |
} | |
@TypeChecked | |
class Prod implements Monoid<Number> { | |
@Override | |
public Number mappend(Number i1, Number i2) { | |
i1*i2 | |
} | |
@Override | |
public Number mempty() { | |
new Integer(1) | |
} | |
} | |
@TypeChecked | |
class ListApplicative extends ListFunctor implements Applicative<List> { | |
@Override | |
public <T> List<T> pure(T t) { // pure :: a -> f a | |
[t] | |
} | |
@Override | |
public <T,R> List<R> ap(List<Function<T,R>> funcs, List<T> t) { // <*> :: f (a -> b) -> f a -> f b | |
(funcs as List<Function<T,R>>).collectMany { func -> | |
t.collect{ func.apply(it) } } | |
} | |
} | |
@TypeChecked | |
class ListMonad extends ListApplicative implements Monad<List> { | |
@Override | |
public <T> List<T> unit(T t) { | |
pure t | |
} | |
@Override | |
public <T,R> List<R> bind(List<T> m, Function<T,List<R>> func) { // (>>=) :: m a -> (a -> m b) -> m b | |
m.collectMany { func.apply(it) } | |
} | |
} | |
@TypeChecked | |
class IntShow implements Show<Integer> { | |
@Override | |
public String show(Integer i) { | |
i.toString(); | |
} | |
} | |
@TypeChecked | |
class StringShow implements Show<String> { | |
@Override | |
public String show(String s) { | |
s; | |
} | |
} | |
@TypeChecked | |
class ListShow<T> implements Show<List<T>> { | |
Show elemShowDict | |
ListShow(/*@Implicit*/ Show<T> showDict) { | |
this.elemShowDict = showDict | |
} | |
@Override | |
public String show(List<T> list) { | |
'['+list.collect{ T it -> elemShowDict.show(it) }.join(',')+']' | |
} | |
} | |
@TypeChecked | |
class IntEq implements Eq<Integer> { | |
@Override | |
boolean eq(Integer t1, Integer t2) { | |
t1 == t2 | |
} | |
} | |
@TypeChecked | |
class IntOrd implements Ord<Integer> { | |
@Override | |
boolean eq(Integer t1, Integer t2) { | |
t1 == t2 | |
} | |
@Override | |
boolean gt(Integer t1, Integer t2) { | |
t1 > t2 | |
} | |
} | |
/*- static function -*/ | |
@TypeChecked | |
class Util { | |
static <T> T mappend(T t1, T t2, /*@Implicit*/ Semigroup<T> dict) { dict.mappend(t1,t2) } | |
static <T> T mempty(/*@Implicit*/ Monoid<T> dict) { dict.mempty() } | |
static <F,T,R> F<R> fmap(Function<T,R> func, F<T> t, /*@Implicit*/ Functor<F> dict) { dict.fmap(func, t)} | |
static <A,T,R> A<T> pure(T t, /*@Implicit*/ Applicative<A> dict) { dict.pure(t) } | |
static <A,T,R> A<R> ap(A<Function<T,R>> func, A<T> a, /*@Implicit*/ Applicative<A> dict) { dict.ap(func, a) } | |
static <M,T,R> M<M> unit(T t, /*@Implicit*/ Monad<M> dict) { dict.unit(t) } | |
static <M,T,R> M<R> bind(M<T> a, Function<T,M<R>> func, /*@Implicit*/ Monad<M> dict) { dict.bind(a, func) } | |
static <T> String show(T x, /*@Implicit*/ Show<T> dict) { dict.show(x) } | |
static <T> boolean eq(T t1, T t2, /*@Implicit*/ Eq<T> dict) { dict.eq(t1, t2) } | |
static <T> boolean neq(T t1, T t2, /*@Implicit*/ Eq<T> dict) { dict.neq(t1, t2) } | |
static <T> boolean gt(T t1, T t2, /*@Implicit*/ Ord<T> dict) { dict.gt(t1, t2) } | |
static <T> boolean lt(T t1, T t2, /*@Implicit*/ Ord<T> dict) { dict.lt(t1, t2) } | |
static <T> boolean ge(T t1, T t2, /*@Implicit*/ Ord<T> dict) { dict.ge(t1, t2) } | |
static <T> boolean le(T t1, T t2, /*@Implicit*/ Ord<T> dict) { dict.le(t1, t2) } | |
} | |
@TypeChecked | |
def func() { | |
Sum sumMonoidDict = new Sum() | |
assert mappend(1, mempty(sumMonoidDict), sumMonoidDict) == 1 | |
assert mappend(1, mempty(sumMonoidDict), sumMonoidDict) == 1 | |
assert mappend(3, 4, sumMonoidDict) == 7 | |
assert mappend(1, mempty(sumMonoidDict), sumMonoidDict) == 1 | |
assert mappend(3, mempty(sumMonoidDict), sumMonoidDict) == 3 | |
Prod prodMonoidDict = new Prod() | |
assert mappend(1, mempty(prodMonoidDict), prodMonoidDict) == 1 | |
assert mappend(3, 4, prodMonoidDict) == 12 | |
assert mappend(1, mempty(prodMonoidDict), prodMonoidDict) == 1 | |
assert mappend(3, mempty(prodMonoidDict), prodMonoidDict) == 3 | |
ListMonoid listMonoidDict = new ListMonoid() | |
assert mappend([1], mempty(listMonoidDict), listMonoidDict) == [1] | |
OptionalMonoid<List> optionalMonoidDict = new OptionalMonoid<List>(listMonoidDict) | |
assert mappend(Optional.of([1]), mempty(optionalMonoidDict), optionalMonoidDict) == Optional.of([1]) | |
assert mappend(mempty(optionalMonoidDict), Optional.of([1]), optionalMonoidDict) == Optional.of([1]) | |
ListFunctor listFunctorDict = new ListFunctor() | |
assert fmap({Integer n -> n*2}, [1,2,3], listFunctorDict) == [2,4,6] | |
ListFunctor listFunctorDict2 = new ListFunctor() | |
assert fmap({Double n -> (Integer)n}, [1.5d,2.2d,3.3d], listFunctorDict2 ) == [1,2,3] | |
OptionalFunctor optionalFunctorDict = new OptionalFunctor() | |
assert fmap({Integer n -> n*2}, Optional.of(3), optionalFunctorDict) == Optional.of(6) | |
assert fmap({Integer n -> n*2}, Optional.empty(), optionalFunctorDict) == Optional.empty() | |
ListApplicative listApplicativeDict = new ListApplicative() | |
assert pure(3, listApplicativeDict) == [3] | |
assert ap([{Integer n->n+2} as Function, {Integer n->n+3} as Function] as ArrayList, | |
[10,20,30], listApplicativeDict) == [12,22,32,13,23,33] | |
ListMonad listMonadDict = new ListMonad() | |
assert unit(10, listMonadDict) == [10] | |
assert bind([10,20,30], { Integer it -> [it+1, it] }, listMonadDict) == [11, 10, 21, 20, 31, 30] | |
assert bind((1..5).collect{(Integer)it}, { Integer a -> | |
bind((1..a).collect{(Integer)it}, { Integer b -> | |
bind((1..a+b).collect{(Integer)it}, { Integer c -> | |
unit("(a=$a,b=$b,c=$c)", listMonadDict) | |
}, listMonadDict) | |
}, listMonadDict) | |
}, listMonadDict).size() == 90 | |
IntShow intShowDict = new IntShow() | |
StringShow stringShowDict = new StringShow() | |
ListShow listShowDict = new ListShow(stringShowDict) | |
assert show(3, intShowDict) == "3" | |
assert show("abc", stringShowDict) == "abc" | |
List<String> list = ["a","b","c"] | |
assert show(list, listShowDict) == "[a,b,c]" | |
IntEq intEqDict = new IntEq() | |
assert eq(1, 2, intEqDict) == false | |
assert eq(1, 1, intEqDict) == true | |
assert neq(1, 1, intEqDict) == false | |
assert neq(1, 2, intEqDict) == true | |
IntOrd intOrdDict = new IntOrd() | |
assert gt(2, 1, intOrdDict) == true | |
assert gt(2, 2, intOrdDict) == false | |
assert gt(2, 3, intOrdDict) == false | |
assert lt(2, 1, intOrdDict) == false | |
assert lt(2, 2, intOrdDict) == false | |
assert lt(2, 3, intOrdDict) == true | |
assert ge(2, 1, intOrdDict) == true | |
assert ge(2, 2, intOrdDict) == true | |
assert ge(2, 3, intOrdDict) == false | |
assert le(2, 1, intOrdDict) == false | |
assert le(2, 2, intOrdDict) == true | |
assert le(2, 3, intOrdDict) == true | |
} | |
func() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment