Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/derive4j/hkt

Higher Kinded Type machinery for Java
https://github.com/derive4j/hkt

annotation-processor functional-programming hk-encoding hkt java-8 typechecker

Last synced: 7 days ago
JSON representation

Higher Kinded Type machinery for Java

Awesome Lists containing this project

README

        

# Higher Kinded Type machinery for Java

[![Gitter](https://badges.gitter.im/derive4j/hkt.svg)](https://gitter.im/derive4j/hkt)
[![Maven Central](https://img.shields.io/maven-central/v/org.derive4j.hkt/hkt.svg)][search.maven]
[![Travis](https://travis-ci.org/derive4j/hkt.svg?branch=master)](https://travis-ci.org/derive4j/hkt)

This project provides type-safety for the higher kinded type encoding demonstrated in https://github.com/highj/highj via a JSR269 annotation processor.

For some theorical explanation of the encoding you may refer to the [Lightweight higher-kinded polymorphism](https://www.cl.cam.ac.uk/~jdy22/papers/lightweight-higher-kinded-polymorphism.pdf) paper.

# Usage

## Choose your HK encoding:

the two basic possibilities are:
```java
class HkTest implements __, A> {...}
```
and
```java
class HkTest
implements __ {
enum w { // could be any name, also could be a static nested class.
}
}
```
We say that `__` is the HK encoding of HkTest
and call `w` the *witness type* of `HkTest`.

## What about binary type constructors ? Ternary ? And more ?

@derive4j/hkt supplies interfaces `__`, `__2` up to `__9`.

For example, a disjoint union type commonly called "Either" could be declared this way :
```java
class Either
implements __2 {
enum µ {}
...
}
```

## Obligatory Monad example:
The higher kinded polymorphism gained by the encoding allows us to express things that are normally inexpressible in Java. Eg.:
```java
public interface Monad {
__ pure(A a);

__ bind(__ ma, Function> f);

default __ map(__ ma, Function f) {
return bind(ma, f.andThen(this::pure));
}
}
```

## Aliases interfaces
You may want to create aliases of derive4j hkt `__*` interfaces that better suit your naming preferences, maybe also adding
some default methods. Eg.:

```java
interface HigherKind1, T> extends __ {
default R transform(Function<__, R> f) {
return f.apply(this);
}
}
```
And so your hk-encoded classes would look like:
```java
class HkTest
implements HigherKind1, A> {...}
```
In any case, just try: if you do something wrong the annotation processor shall help you!

## A note on safety : do not cast! Use the generated safe cast methods
By default the annotation processor will generate a `Hkt` class in each package that contains hk-encoded classes.

The generated class contains casting methods and factories of [TypeEq](src/main/java/org/derive4j/hkt/TypeEq.java) that allow you to safely recover the original type from its hk-encoding.

Here is an example :

- given the HKT types
```java
class Maybe
implements __ {...}
```
and
```java
class List
implements __ {...}
```
both in package `myorg.data`

- then the following class will be generated
```java
package myorg.data;

final class Hkt {
private Hkt() {}

static
Maybe asMaybe(final __ hkt) {
return (Maybe
) hkt;
}

static
List asList(final __ hkt) {
return (List
) hkt;
}
}
```

Now you may ask : why is that safe ? I could implement `__` in my `Foo` class, pass an instance of it to `Hkt.asMaybe` and then boom !

And to this the answer is no, you can't. That's the whole point of the hkt processor : would you try to implement `__` in any other class than `Maybe`, you'd get a **compile time** error.

The processor thus ensures that the only possible implementation of `__` is `Maybe` : hence the safety of the cast in the generated methods.

## Configuration of code generation

Code generation can be customized by using the [HktConfig](src/main/java/org/derive4j/hkt/HktConfig.java) annotation (on
package-info or classes).

Consider the example of the previous section : we would like the generated methods to be called `toX` instead of `asX`. Easy ! Just declare, in the `myorg.data` package, a `package-info` file as such :
```java
@HktConfig(coerceMethodName = "to{ClassName}")
package myorg.data;
```

Note that configuration is handled hierarchically through packages, classes and inner classes. That means that would you want to keep your `toX` methods and at the same time have the one for `List` generated in its own class, you could declare a `package-info` as afore mentionned and then annotate the `List` class this way:
```java
@HktConfig(generateIn = "MyHktList")
class List
implements __ {...}
```
As expected, the following two files would then be generated :
```java
package myorg.data;

final class Hkt {
private Hkt() {}

static
Maybe toMaybe(final __ hkt) {
return (Maybe
) hkt;
}
}
```
and
```java
package myorg.data;

final class MyHktList {
private MyHktList() {}

static
List toList(final __ hkt) {
return (List
) hkt;
}
}
```

## I want it !

### Maven
```xml

org.derive4j.hkt
hkt
0.9.2

```
[search.maven]: http://search.maven.org/#search|ga|1|org.derive4j.hkt

### Gradle
```
compile(group: 'org.derive4j.hkt', name: 'hkt', version: '0.9.2', ext: 'jar')
```