JSON mapping and reader monad [DRAFT]

Functional JSON mapping became a hot theme recently. Clear declarative syntax backed by cryptic concepts of monads and applicative functors has exploded many heads.
I’d like to talk about a little refinement of our mapping pattern to better isolate mapping algorithms from actual data.

Let’s start with some simple mapping code:

struct User {
let name: String
let age: Int

static func build(name: String)(age: Int) -> User {
    return User(name: name, age: age)
}

}

// TODO: write operators

let JSON = [“name”: “Sergei”, “age”: 30]
let user = User.build >> stringForKey(JSON, “name”)
>>> intForKey(JSON, “age”)

The thing that bothers me is coupling of input JSON with our mapping logic. What if we could rectify our mapping to remove this dependency?

Let’s introduce a Reader monad. The simple idea behind is expressing our computation as a function of our JSON parameter and once we need it, “running” it bound with data.

struct Reader {
let value: T -> U

func run(t: T) -> U {
    return value(t)
}

}

Here we express some value U as a function of T and store it in a type safe manner. Here’s how we use it:

func intForKey(key: String) -> Reader {
return Reader({ $0[key] as? Int })
}

See how our dependency on JSON is extracted and moved somewhere to a future?

Once we redefine our lifting and binding operators for Reader<>, we end up with the same mapping code:

let parse = User.build >> stringForKey(JSON, “name”)
>>> intForKey(JSON, “age”)

The only difference is it returns Reader instead of User?. To get User we need to bind it with JSON:

let user = parse.run(JSON)

This approach greatly facilitated code reuse via enabling to define algorithms instead of plain transforms on data.

 
0
Kudos
 
0
Kudos

Now read this

Thread safe variable access, functional way. Part I.

Correctness of the threaded code has always been a concern. The common pattern is guarding some shared state with a serial dispatch queue: func setCounter(value: Int) { dispatch_async(syncQueue) { self.counter = value } } func... Continue →