Akh 3 – The Splittening

Akh so! Akh 3 is out now.

$ npm install --save akh

Links

Akh is a Javascript collection of monads and monad transformers inspired by MTL. Version three brings some new types to the party, breaks the collection up into a set of proper npm packages, and gives the API a quick dusting. Let’s take a quick look at the key changes.

Cleaner API

Back in the bad old Akh 2 days, you had to write imports like this:

// Akh 2
const EitherT = require('akh').trans.either

Akh 3 simplifies imports and namespaces so that you now write:

// Akh 3 
const EitherT = require('akh').EitherT
// or even
import {EitherT} from 'akh'

The old require('akh').base helper functions have also now all been moved to top level exports:

// Akh 2
const liftM = require('akh').base.liftM

// Akh 3
const liftM = require('akh').liftM

Also, the names of the various run/extract methods have been simplified and you can now even use them as methods:

// Akh 2
const List = require('akh').type.list
List.runList(List.of(2))

// Akh 3
const List = require('akh').List
List.run(List.of(2))
// or even
List.of(2).run()

Packages for Everything

The core akh npm package still wraps up all your favorite types, such Either and Cont, but you can now also consume those types through individual npm packages:

// Use Either as part of main Akh library
const Either = require('akh').Either

// Only import just the Either type
const Either = require('akh.either').Either

This allows specifying lighter-weight, more targeted dependencies. It should also make it easier to maintain and iterate on the core type implementations (he says optimistically), and make it easier to extend Akh.

Here’s the list of official types and their packages, as of version 3.1:

Maybe, Reader, and Writer

Akh 3.1 brings friends Reader, Writer, and Maybe into the core collection, along with their transformer progenitors ReaderT, WriterT, and MaybeT.

Maybe and MaybeT from akh.maybe should be familiar enough. MaybeT extends an underlying value to support optional values while Maybe brings this logic on its own. Here’s a classic example:

const Maybe = require('akh').Maybe

const safeDiv = (x, y) =>
    y === 0 ? Maybe.nothing : Maybe.just(x / y)

Maybe.just(3)
    .chain(x => safeDiv(12, x))
    .map(x => x * x)
    .maybe('default') === 16  // extract value or return 'default' if none
    
Maybe.just(0)
    .chain(x => safeDiv(12, x))
    .maybe('default') === 'default'

Reader and ReaderT from akh.reader allow reading from a shared environment:

const Reader = require('akh').Reader

Reader.asks(r => r.a)
    .map(x => x * 2),
    .run({ a: 10, b: 3 }) === 20

Writer and Writer from akh.write allow producing a value along with a list of output values:

const Writer = require('akh').Writer
const List = require('akh').List;

const r = Writer.tell(List.of(1)) // append to output
    .censor(x => x.concat(List.of(5))) // modify output
    .map(_ => 'result')
    .run(List.zero)

r.value === 'result'
r.output.run() == [1, 5] // Extract array from the List using `run()`

Issues / Feedback

So if you wish your Javascript had some monad transformers, give Akh a try. (Admittedly, that target market may be close to one, but oh well.)

Please let me know if you run into any problems, have any suggestions, or would like to contribute to Akh’s development. I’ve also tried to clean up the documentation to make it easier to get started.