This projects tries to bring proper functional elements to Java through annotation processing.
You need to annotate the class that is implementing such a
structure with the correct annotation. For example @Functor
to implement IFunctor
.
A functional structure is a set of operations defined over a type constructor or set of type constructors
To create use it you just need to implement the needed interface, like IFuntor<List<?>>
substituting IFunctor
and List
for the functional structure
and the type constructor you would like to use. The type constructor needs to use
the wildcard ?
. Note that we may use type constructors with several inputs like
Either<A,?>
or Either<?,?>
.
It is not possible to concatenate constructors as in Maybe<List<?>>
An algebraic structure is a set of operations defined over a type or set of types. They are type constructors, but they still require the corresponding annotation.
As the last step, add the annotation processor com.dan323.functional.annotation.FunctionalCompiler
to your project.
Compilation will fail until you add enough methods to satisfy the functional and algebraic structure requirements.
An algebraic structure is a set of operations defined over a type or set of types. Methods of super-types also count towards the annotation being implemented.
A semigroup requires only one operation
@Semigroup
public interface ASemigroup<T> extends ISemigroup<T> {
T op(T a, T b);
}
and it should satisfy the associative property:
op(x,op(y,z)) == op(op(x,y),z)
A monoid is a semigroup with a neutral element:
@Monoid
public interface AMonoid<T> extends IMonoid<T> {
T unit();
}
and it should satisfy the neutral property:
op(x, unit()) == x
op(unit(), x) == x
A functor requires only one function
@Functor
public interface AFunctor extends IFunctor<F<?>> {
<A,B> F<B> map(F<A> base, Function<A,B> map);
}
and it satisfies the following laws:
map(x, id) == x
map(map(x, f), g) == map(x, g . f)
The miminal required is the only function it has: map
Any applicative is a functor, so it also has a map function added to the following:
@Applicative
public interface AnApplicative extends IApplicative<F<?>> {
<A> F<A> pure(A a);
<A,B> F<B> fapply(F<Function<A,B>> map, F<A> base);
<A,B,C> F<C> liftA2(BiFunction<A,B,C> map, F<A> fa, F<B> fb);
}
and it satisfies the following laws (adding the ones from functor):
fapply(pure(f), base) == map(base, f)
map(g, pure(x)) == pure(g(x))
fapply(u, pure(y)) == fapply(pure(f -> f(y)), u)
liftA2(f, a, b) == fapply(map(f, a), b)
fapply(f,base) == liftA2((a,b) -> a(b), f, base)
The mimimal required is pure and, either fapply or liftA2.
Any monad is an applicative, and hence a functor, so it has all their functions plus the following:
@Monad
public interface AMonad extends IMonad<F<?>> {
<A,B> F<B> flatMap(Function<A,F<B>> map, F<A> base);
<A> F<A> join(F<F<A>> doubleMonad);
}
and it satisfies the following laws (adding the ones from applicative):
flatMap(id, ffa) == join(ffa)
flatMap(pure . f, base) == map(f, base)
fapply(f, base) == flatMap(g -> map(g, base), f)
join(pure(fa)) == fa
The minimal required is pure and one of the following lists:
- flatMap
- join and the minimal Functor
- join and the minimal Applicative
A foldable structure is one we can collapse. Up to now it has 3 functions defined:
@Foldable
public interface AFoldable extends IFoldable<F<?>> {
<A> A fold(IMonoid<A> monoid, F<A> a);
<A, M> M foldMap(IMonoid<M> monoid, Function<A,M> function, F<A> base);
<A, B> B foldr(BiFunction<A,B,B> function, B b, F<A> fa);
}
and they satisfy the following laws:
fold(m, b) == foldMap(m, Function.identity(), b)
foldr(f, z, t) == (foldMap(EndoMonoid, f, t))(z)
foldMap(m, f, b) == foldr((x,y) -> m.op(f(x), y) , m.unit(), b)
where EndoMonoid(A) is the monoid defined over the functions from and to A with op(f,g) = f . g
The minimal required is foldr or foldMap
TODO
TODO