Flow doesn’t support **higher kinded types**: https://github.com/facebook/flow/issues/30.

What does it means in practice?

Here’s a **functor** in PureScript

`class Functor f where`

map :: forall a b. (a -> b) -> f a -> f b

Let’s try to translate the concept to Flow

`interface Functor<F> {`

map<A, B>(f: (a: A) => B, fa: F<A>): F<B>

}

Unfortunately Flow raises the following error

`map<A, B>(f: (a: A) => B, fa: F<A>): F<B>`

^^^^ Incorrect number of type parameters (expected 0)

There’s no way to define *F* as a **unary type constructor**, see Kind (type theory)

interface Functor<F<*>> {

map<A, B>(f: (a: A) => B, fa: F<A>): F<B>

}interface Functor<F<*>> {

^ Unexpected token <

Here I present a way of faking higher kinded types based on the paper Lightweight higher-kinded polymorphism and inspired by elm-brands.

# The recipe

First let’s define an helper class *HKT* that represents a unary type constructor

`class HKT<F, A> {}`

Note that *F* and *A* are phantom types.

Now I can define the functor **type class** without Flow complaining

`interface Functor<F> {`

map<A, B>(f: (a: A) => B, fa: HKT<F, A>): HKT<F, B>

}

As an example, let’s implement the *Maybe* functor, we need

- a nominal type for
*F*(let’s call it*IsMaybe*) - a way to put a value of type
*?A*into*Maybe<A>*(let’s call it*inj*) - a way to get back the value from
*Maybe<A>*(let’s call it*prj*)

class IsMaybe {}type Maybe<A> = HKT<IsMaybe, A>;function inj<A>(a: ?A): Maybe<A> {

return ((a: any): Maybe<A>)

}function prj<A>(fa: Maybe<A>): ?A {

return ((fa: any): ?A)

}

Finally we can implement the functor instance

const Nothing: Maybe<any> = inj(null)function map<A, B>(f: (a: A) => B, fa: Maybe<A>): Maybe<B> {

const a = prj(fa)

return a == null ? Nothing : inj(f(a))

}map(n => n + 1, Nothing) // => null

map(n => n + 1, inj(3)) // => 4

Using this trick I wrote an implementation of common algebraic types: flow-static-land