[web-devel] Yesod's Route as a data family

Matt Brown matt at softmechanics.net
Wed Nov 10 07:43:59 CET 2010


Hi all,

I'm trying to create a yesod subsite with "private" urls.  The subsite
exports widgets which reference the urls, but the urls are not
intended to be referenced from the master site handlers directly.  In
order for this to work, the sub site needs to know how to translate
it's urls into master urls.  I didn't like passing the subsite route
as a parameter to every widget function, so I tried a class:

class YesodSubRoute sub master where
  subRoute :: Route sub -> Route master

After confronting the dreaded "type families are not injective" error
(i.e. "sub" cannot be inferred from "Route sub", etc), I rewrote it
as:

class YesodSubRoute sub master where
  subRoute :: sub -> master -> Route sub -> Route master

This works, but seems a bit cludgy to me.  Looking closer, I realized
that mkYesodGeneral never reuses types for Route instances, which
means Route actually is injective (as long as instances are only being
defined by mkYesodGeneral), the typechecker just doesn't know it.

As an experiment, I changed Route to a data family.  It went rather
smoothly, and I was able to use my original definition of
YesodSubRoute (instances of which could in theory be generated by
mkYesodGeneral).  The only trouble I've had is exporting Route
instance constructors imported from another package (specifically
yesod-auth in my case), which means every module referencing auth
routes has to import Yesod.Helpers.Auth).

Relevant commits are below.  Does this seem like a sensible approach?
Are there better alternatives?

thanks,
-matt

https://github.com/softmechanics/yesod/commit/335722b6b234841492a6fba2eb46bdf87b86daad
https://github.com/softmechanics/yesod-auth/commit/baf9b44978aad4dba9b86cfafa2a038d95aa11e3


More information about the web-devel mailing list