FSharp.Data.Mutator

jkone27
5 min readJun 19, 2021

--

Mmmm immutable OK, but, can you make my life easy?

You have been doing F# great, and you love Type Providers, especially the
awesome FSharp.Data. Unfortunately Json provided types from FSharp.Data are immutable, and here is the whole focus of this post. Give me that “mutation”!

Introducing FSharp.Data.Mutator

This library in pre-release on nuget (preview beta package) gives you a usable tool for copy mutation now working with JsonValue and FSharp.Data.JsonProvider provided types.

Here is how it looks in action!

#r "nuget:FSharp.Data.Mutator,0.1.0-beta"open FSharp.Data
open FSharp.Data.Mutator
[<Literal>]
let jsonTest =
"""
{
"name":"hey",
"nested": {
"another" : "val"
},
"items" : [
{ "first" : 1 }
]
}
"""
type TestJsonProvided = JsonProvider<jsonTest>TestJsonProvided.GetSample().Change(fun x -> x.Name = "bye")//or if you want to pipe several mutationsTestJsonProvided.GetSample()
|> Change <@ fun x -> x.Name = "one" @>
|> Change <@ fun x -> x.Nested.Another = "two" @>
|> Change <@ fun x -> x.Items.[0].First = 500 @>

Outputs:

val it : JsonProvider<...>.Root =
{
"name": "one", //altered, was hey
"nested": {
"another": "two" //altered, was val
},
"items": [
{
"first": 500 //altered, was 1 before
}
]
}

It’s a first draft and would like to remove some dependencies like Newtonsoft.Json, but overall this library allows you to create strongly typed mutation copies of your sample Json data.

This reduces the gap in many scenarios and keeps it “safe”, not making any real mutation, in a similar way of Lenses concept from what’s my understanding of it.

Note this is strongly typed, but also allows you you to alter JsonValue nodes directly if you need for any reason, “jumping out” of the actual schema, so it’s still schema-less like json is supposed to be.

FSharp.Data

The FSharp.Data package implements core functionality to access common data formats in your F# applications and scripts. It contains F# type providers for working with structured file formats (CSV, HTML, JSON and XML) and helpers for parsing CSV, HTML and JSON files and for sending HTTP requests.

It powers your productivity while writing script or apps, and saves you lots of typing keeping errors out of the way with static typing validation, It’s not a case the paper for type providers was mentioned in ACM papers. What’s ACM?
LOL, that’s the Turing Award institution, yes…

FSharp.Data stems from Types from data Making structured data first-class citizens in F# by Petricek, Syme and Guerra. This paper received a Distinguished Paper award at PLDI 2016 and was selected as one of three CACM Research Highlight in 2018. 🏆🏆🏆

A real nice application of type providers is in my view also DTO modelling (or controller models in MVC).

Why? as in JS apps json is native, whereas in other langs we traditionally need a model to be serialised/deserialized to/into, an input/output DTO class (in DDD terms).

Immutability, Always?

What if we wanted to mutate our Erased provided types given by FSharp.Data.JsonProvider for example? Well, the thing is, we “shouldn’t” as like we all know in functional programming

Mutation is Evil.

But isn’t evil relative to its context, what if I have some script or some integration tests, where I want to generate several different cases based on a sample or mutate very big json data in several different spots…

Sure I could build huge custom functions to do that every time for every type I eventually want to change with copy mutation, even eventually using something like Lenses for the effort.

Worst, I could decide to map to some other, new user defined type like a record Let’s nullify the type provider effort! What a smart choice.

But, is it really worth to have all this “mutation protection”, it if the actual mutation wouldn’t give me any unwanted dangers?

I do not want to type all that extra clutter, especially if I am scripting, as I am loosing all benefits of type providers too, if you see what I mean! by writing extra types and mapping functions all the times.

In — “I mutated memory” so what, I was doing integration tests, and I am not in production — I think express the sometimes frustrating aspect of being too strict with immutability.

In general I love the F# philosophy of “functional first”, which encompasses immutable first for referential transparency. It is the perfect default, and saves a lot of unwanted mistakes, but thank god we have the mutable keyword.

Do we really want to implement monads and stuff just to like, print to a screen or alter a memory location, when we know is the right thing to do in that case? If yes, let me understand why, as I never got that… really. I make amends

I think sometimes unfortunately libraries and frameworks don’t obey to this general F# philosophy (of letting devs decide when it’s the case to be impure).

A Bigger Rant On Type Providers

Type providers can help us solve this Object JSON (contract) Impedance mismatch for us, so type providers can be seen as “smart-ass” compiler OJM (object json mapper) or ODM (object dto mapper), coining terms here :) probably wrong from a theoretical perspective but you get the idea, if you make a parallel with ORM (object relational mapper).

The mismatch/gap in case of json vs a type/class ofc is much “shorter” compared to a language mismatch like SQL and OO langs, as it’s already an object in just another representation, with .xml also could be said the same, or even .proto files.

Another advantage of Type Providers is in Contract First development, and in a way, constant integration testing just by compiling, if you also “get” what I mean here.

This can be for example the case of the amazing Swagger Provider which provides types for OpenApi v2 and v3 Specifications.

That said, Have Fun!

--

--