Skip to content

Instantly share code, notes, and snippets.

@uehaj
Last active August 29, 2015 14:08
Show Gist options
  • Save uehaj/5d88051646f8e1a6b12f to your computer and use it in GitHub Desktop.
Save uehaj/5d88051646f8e1a6b12f to your computer and use it in GitHub Desktop.
TypeClass for groovy
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