I’m creating yet another functional java library, called jFunc. Why would I do such a thing, we already have cycylops-react and highj why would i waste my time creating another one. A better question is why not, and maybe an even better question would be why don’t we just all program in haskell. But it began by me just trying to grasp concepts in haskell and the funcitonal paradiams presented there in. This is my attempt at making useful documentation for jFunc.
jFunc is a functional java library by functional I mean the libray containes data types that are immutable and lazy. Along with lots of tools to create composble operations and functions.
Persistent Data Structures
FList
FList is immutable and Lazy, FList is analogous to a stream of values.
Becuase FList is lazy we can create infinite list of elements. The below example is an infinite lists of even numbers.
FList<Integer> evenNumber = start(2).filter(i -> i % 2 == 0);
Below is an example of creating an infite list of prime numbers.
public static boolean isPrime(Integer i) {
final int sqrtOfi = (int)Math.sqrt(i);
return allTrueWhile(primes, p -> p <= sqrtOfi
, p -> i % p != 0);
}
public static FList<Integer> primes = flist(2, 3, () -> start(4).filter(Numbers::isPrime));
print(primes.take(12)); //[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]
DList
DList also known as a difference list support constant time append, unlike FList where append is O(n) where n is the numbr of elements in the FList.
If an algorithm builds a list by appending smaller lists repeatdly then DList can greatly improve performnace.
Either
Either is paramatized by two types. Each parameter represents a possible value that the Either can hold, so a Either<L,R> can contain a value of type L (the left value) or a value of type R (the right value).
The Either type is vary useful for describing computation that can return one of two possible values, makeing it very useful for error handling.
In the below code userRead checks a if a username exists, returning a type of Either<Exception,User>. If the the user name ecautally exist then the either contains a User otherwise it contains an Exception.
@POST
@Path("/login")
@Produces(MediaType.APPLICATION_JSON)
public Response getToken(Login login) {
EntityManger em = getEntityManager();
Either<Exception, User> userRead =
read(User.class, login.username)
.runAndClose(em);
Either<Response, Response> response =
userRead.bimap(forbidden,validate.call(login))
return either(response);
}
bimap(F1<L,A> left, F1<R,B> right) maps the two given functions to the contains of the either the function the is mapped over the contnents of the eiterh depened on if the either has a left value or a right value.
forbidden and validate both return a type of Response because of this we can use either(Either<R,R> either) either return the left or right value within an either, we can use either when the left and right value are the same type. Theres no need to inspect the content of the either since we transform the left and right sie of the either into the approritea reposone.
public static F1<Excpetion,Response> forbidden =
e -> Response.status(Response.Status.FORBIDDEN).entity(new ErrorResponse(e.getMessage())).build();
public static F2<Login,User,Response> validate =
(l,u) -> {
String ps = u.getPassword();
if (ps.equals(l.password)) {
return Response.ok().entity(tokenGen(u)).build();
} else {
return Response.status(Response.Status.UNAUTHORIZED).build();
}
};
Maybe
Maybe is a control structure that repesent a value that is something or nothing. We can refactor functions that may return null with Maybe.
public static F2<Integer, Integer, Maybe<Integer>> div = (num, den) -> {
if(den == 0)
return Maybe.noting();
else
return Maybe.maybe(num / den);
}
Because dividing by zero would result in an error we may return a Maybe containing nothing. We can bind and map over the returned Maybe to manipulate the possible value within the value.
publilc static F2<Integer, Integer> double = i -> 2 * i;
Maybe<Integer> num = div.call(4, 2);
num.map(double); // Maybe 4
num = div.call(4, 0);
num.map(double); // Nothing
Tuples
Similar to FList Tuples are a sequence of values unlike FList a tuple is heterogenous and has a fixed length. jFunc’s Tuples may have a size of 2 to 8(T2, T3, T4, T5, T6, T7, T8)
Map TODO
Functions
F0-F8
jFunc has functional interfaces for functions from arity 0 to 8(F0, F1,F2, F3, F4, F5, F6, F7, F8). all functions can be paritablly applied.
F2<Integer, Integer, Integer> add = (i, i1) -> i + i1;
F1<Integer,Integer> add3 = add.call(3);
F1<Integer,Integer> add4 = add.call(4);
Integer seven = add3.call(0) + add4.call(0);
Integer seven$ = add.call(3,4);
//seven == seven$
P1-P8
jFunc contains functional interface for functins that speciifcally return boolean values. These interfaces are called predicates(P1, P2, P3, P4, P5, P6, P7, P8). P1 is a predicate of arity one, P2 is a pridctaice of arity two and so on.
Trampoline
public static Trampoline<BigInteger> fib(Integer i) {
return fib_prime(BigInteger.ZERO, BigInteger.ONE, i);
}
public static Trampoline<BigInteger> fib_prime(BigInteger a, BigInteger b, Integer i) {
if(i == 0) return done(a);
if(i == 1) return done(b);
return fib_prime(b, a.add(b), i - 1);
}
public static Trampoline<BigInteger> fact(BigInteger n) {
if(n.equals(BigInteger.ZERO))
return done(BigInteger.ONE);
else if(n.equals(BigInteger.ONE))
return done(BigInteger.ONE);
else{
return more(() -> {
return fact(n.add(BigInteger.ONE.negate())).map(i -> n.multiply(i));
});
}
}
Eval
Eval allows the evaluation of expressions to be derfered, additionall the computed value is cached for later use.
Example To Come
Exception Handling
Try
Try0-Try8
Monads
MaybeT
Example To Come
ReaderT
Example To Come
WriterT
Example To Come
StateT
The StateT monad allows for the threading of some state through a series of functions.
/*
* Example use of State monad
* Passes a string of dictionary {a,b,c}
* Game is to produce a number from the string.
* By default the game is off, a C toggles the
* game on and off. A 'a' gives +1 and a b gives -1.
* E.g
* 'ab' = 0
* 'ca' = 1
* 'cabca' = 0
* State = game is on or off & current score
* = (Boolean, Int)
*/
public static State<T2<Boolean,Integer>, Integer> playGame(FList<Character> s) {
return CaseOf.caseOf(s)
.of( FList::isEmpty, () -> State.<T2<Boolean,Integer>>get().bind(t -> ret(t._2())) )
.otherwise( list -> {
return State.<T2<Boolean,Integer>>get()
.bind(t -> {
boolean on = t._1();
int score = t._2();
return CaseOf.caseOf(list.head())
.of(eq('a').AND(on), () -> put( T2.t2( on, score + 1) ) )
.of(eq('b').AND(on), () -> put( T2.t2( on, score - 1) ) )
.of(eq('c') , () -> put( T2.t2(!on, score ) ) )
.otherwise( () -> put( T2.t2( on, score ) ) )
.semi(playGame(list.tail()));
});
});
}
public static void main(String[] args) {
T2<Boolean,Integer> initState = T2.t2(false,0);
Integer i = playGame(flist('c', 'a', 'b', 'c', 'a'))
.evalState(initState);
System.out.println(i); // 0
}
The above code snippets are translation of Haskell code found here.