[Haskell-cafe] Updating code to work with vinyl 0.4

Mateusz Kowalczyk fuuzetsu at fuuzetsu.co.uk
Mon Aug 11 09:43:58 UTC 2014


I'm looking for some help in helping to migrate to vinyl-0.4 from
earlier version. I'll first outline how I currently have things set up
and then ask a few questions. For reference the whole project is at [1].
You can just skip to questions in the end if you want to.

I have a small project which goes out to a few sites, fetches some
similar XML data, parses some fields and returns a data type. My
original attempt was to generate a data type per site but that was very
ugly: couldn't reuse functions, accessors, anything. So I then turned to
vinyl and have the following solution:

I have a bunch of common fields defined like this:

file_url ∷ "file_url" ::: String
file_url = Field

parent_id ∷ "parent_id" ::: Maybe Integer
parent_id = Field
and so on.

I'm using HXT to process the XML I get from each site so I have created
many HXT arrows creating each field like this:

parent_idA ∷ (Functor (cat XmlTree), ArrowXml cat) ⇒
             cat XmlTree (PlainRec '["parent_id" ::: Maybe Integer])
parent_idA = (parent_id =:) . readMaybe <$> getAttrValue "parent_id"

Then for each site I define records like this

type GelbooruPost = PlainRec
  '[ "height" ::: Integer
   , "score" ::: Integer
   , "file_url" ::: String
   , "parent_id" ::: Maybe Integer
   , …

and create the final HXT arrow which will parse and run my value parsers
on the whole output

parsePost ∷ (Functor (cat XmlTree), ArrowXml cat) ⇒ cat XmlTree GelbooruPost
parsePost = hasName "post"
  >>> heightA <:+> scoreA <:+> file_urlA <:+> parent_idA <:+> sample_urlA
  <:+> sample_widthA <:+> sample_heightA <:+> preview_urlA <:+> ratingA
  <:+> tagsA <:+> idA <:+> widthA <:+> changeA <:+> md5A <:+> creator_idA
  <:+> has_childrenA <:+> created_atA <:+> statusA <:+> sourceA <:+>
  <:+> has_commentsA <:+> preview_widthA <:+> preview_heightA

This works OK: I have similar records for each site and vinyl let me use
the same accessors to work over the data from each site without much
hassle even though they all return slightly different things. But now
vinyl-0.4 is out and I have to update but I'm struggling.

As per tutorial I converted all my fields to this format:

data Fields = Height | Score | FileUrl | ParentId | SampleUrl | …

Then generated singletons and made universe:

genSingletons [ ''Fields ]
makeUniverse' ''Fields "ElF"
semantics ''ElF [ 'Height :~> ''String
                , 'Score :~> ''Integer
                , 'FileUrl :~> ''String
                , 'ParentId :~> ''Integer -- Maybe Integer
                , 'SampleWidth :~> ''Integer
                , 'SampleHeight :~> ''Integer
                , 'PreviewUrl :~> ''String
                , 'Rating :~> ''Rating
                , 'Tags :~> ''String -- [String]

As you can see I have a problem here already: I don't know how to
specify ‘Maybe Integer’ or ‘[String]’ in the way that is accepted.
Previously I would just do "tags ::: [String]" and it worked.

I also wonder what things like:

PlainRec '["parent_id" ::: Maybe Integer])

now become. “PlainRec ElF (ParentId ': '[])” works but is ugly, is there
a shorthand for singletons? This is assuming I can convince the ParentId
field to be Maybe Integer.

Lastly I'd like to know why trivial examples such as this

a ∷ PlainRec ElF (Score ': '[])
a = SScore =: 7

require a type signature. While I put down the signatures anyway, I
wonder if there's a way to skip them. I suppose using the field in an
annotated record somewhere might let me do this. I imagine the problem
here is that we need to specify ElF.

Perhaps I am meant to approach this whole thing differently which is why
I laid out the structure a bit rather than just asking about syntax. I
have watched the video at [2] and while the new records do sound better,
I can't find a good guide on how to use them. The tutorial on GitHub[3]
is rather lacking. If someone knows about more guides then I'd love to
hear about that too.


[1]: http://github.com/Fuuzetsu/h-booru
[2]: http://vimeo.com/102785458
[3]: https://github.com/VinylRecords/Vinyl/blob/master/tests/Intro.lhs

Mateusz K.

More information about the Haskell-Cafe mailing list