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

adam vogt vogt.adam at gmail.com
Mon Aug 11 15:04:47 UTC 2014


Hi Mateusz,

You can write  'Foo :~> [t| Maybe String |] to make the generated code include a

  type instance App ElF Foo = Maybe String

Unfortunately the type of (:~>) includes some un-exported classes, so
you have to dig into vinyl's source to see which arguments are
actually allowed.


I'm not sure exactly what you mean by

> PlainRec ElF (ParentId ': '[])” works but is ugly

But maybe it's worth just using the Data.Vinyl.Universe.Field (ex.
http://lpaste.net/109203), if you would rather write

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

than,

  PlainRec ElF '[ParentId]

Or maybe you want to use Symbol together with your own universe:

  makeUniverse' ''Symbol "ElF"
  semantics ''ElF [ [t| "height" |] :~> [t| Maybe Int |] ]
  -- type instance App ElF "height" = Maybe Int -- or just write those by-hand

  height = Proxy :: Proxy "height" -- there seems to be no code
generation in Vinyl for these

which will give you a type like

  PlainRec ElF '["parent_id"]

Hopefully one of these options is not as ugly as the other.


Regards,
Adam

On Mon, Aug 11, 2014 at 5:43 AM, Mateusz Kowalczyk
<fuuzetsu at fuuzetsu.co.uk> wrote:
> Hi,
>
> 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_notesA
>   <:+> 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.
>
> Thanks!
>
> [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.
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe


More information about the Haskell-Cafe mailing list