align-toparrow-leftarrow-rightbackbellblockcalendarcamerachatcheckchevron-downchevron-leftchevron-rightchevron-small-downchevron-small-leftchevron-small-rightchevron-small-upchevron-upcircle-with-crosscrosseditfacebookglobegoogleimagesinstagramlocation-pinmagnifying-glassmailmoremuplabelShape 3 + Rectangle 1outlookpersonplusImported LayersImported LayersImported Layersshieldstartwitteryahoo

Hoodlums Message Board › Homework: JSON quasi-quoter

Homework: JSON quasi-quoter

Peter M.
Group Organizer
London, GB
Post #: 45
I've posted the code from our last session here.

Your mission, should you choose to accept it, is to add anti-quoting. We started trying to do this at the session but got into a bit of a mess. I've included some notes here that may help. I've tried to organise them in order, so you can start with the first ones and read on if you need more guidance.

If I get time, I'll do a version and we can go through it next week... yes it is only a few days away.


Notes (possible spoiler alert)

The Haskell parser that produces expressions in Template Haskell's Exp type is in the package haskell-src-meta.


Francesco was, of course, entirely correct that we can't do anything useful with Exp values whilst parsing to a JSValue structure, so we have two options:

We could change the parser to produce Exp structures rather than JSValues. This would work and would be quite simple, but it seems a shame that we need two completely separate parsers, one for parsing JSON at runtime and one for parsing JSON, with anti-quoting, at compile time. I'd really like to be able to use the same code for both purposes. Which is what we started trying to do at the session.

Our other route is to unfix the JSValue type in a similar way to how we unfixed the parser. Of course if we were designing the JSON package ourselves we would have unfixed the type in the first place. Whilst using the unfixed type is a little clumsier than the original, it means that we get generalized recursion goodness for free (we did a couple of sessions on catamorphisms and friends a few months back). It's a shame that none of the 17 or so JSON packages out there seem to have done this.


To unfix the type, we do just the same as we did with the parser: we copy the original module, add an extra parameter, r, then replace all recursive references with r.

And just as with the parser, we can fix our unfixed type. This time using the newtype:

newtype Fix f = Fix (f (Fix f))

There are plenty of things that will need to be modified, but it should be reasonably easy to get the quasi-quoter working again... still without anti-quoting.


Now it is time for the Free Monad. Well actually, we aren't going to use it as a monad, but the data structure fits our purposes nicely. There are many variations on naming used, but we want something like:

data Free f a = Pure a | Free (f (Free f a))

Notice that the second constructor is identical to Fix, but with the extra type parameter. This allows us to fix our structure and intersperse values of some other type wherever we want. Hopefully, you can see how that will help us.

I haven't tried this yet, but we should be able to write the JSON parser in such a way that it can be used to produce JSValues fixed up with Fix or Free, depending on what parser we give it to recurse with.


The rest should be quite easy, we write the anti-quote parser to produce an Exp and create a parser that will parse either an anti-quote, which it wraps with Pure, or a JSValue which it wraps with Free.

Then all we should need is the Lift instance for Free and we should be good to go.


What is cool about this is that we have an anti-quoter that can be used in any quasi-quoter that parses to an unfixed datatype.
Tim W.
user 12343318
London, GB
Post #: 10

Hi all,

I had a brief stab at following Peter's advice just now and the approach works really well. For example:

main = do
let s = "foo"
let x = 1
putStrLn $ show [$json|[ $(jsstr $ s++"bar"), $(jsrat $ x + 1)]|]

prints out:

Fix (JSArray [Fix (JSString (JSONString {fromJSString = "foobar"})),
Fix (JSRational False (2 % 1))])

Note that I only use the Free monad structure for parsing; and I created some utility functions to allow me to create succinct anti-quoted expressions of different JSON types.

UPDATE: My parser was incorrectly coupled to the Free Monad

Peter M.
Group Organizer
London, GB
Post #: 46
I've posted my implementation here. This is the code we went through at this month's session.
user 12935907
London, GB
Post #: 1
Could you post up the code that was written for the new problem please.

Powered by mvnForum

People in this
Meetup are also in:

Sign up

Meetup members, Log in

By clicking "Sign up" or "Sign up using Facebook", you confirm that you accept our Terms of Service & Privacy Policy